/*
 * SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
 *
 * SPDX-License-Identifier: MulanPSL-2.0
 */
#![allow(
    non_camel_case_types,
    unreachable_code,
    unused_assignments,
    unused_mut,
    non_upper_case_globals,
    non_snake_case,
    clashing_extern_declarations,
    dead_code,
    clippy::double_parens,
    clippy::never_loop
)]

#[macro_use]
mod common;

mod conversation;
mod copy_file;
mod env_hooks;
mod exec;
mod exec_common;
mod exec_monitor;
mod exec_nopty;
mod exec_pty;
mod get_pty;
mod hooks;
mod limits;
mod load_plugins;
mod net_ifs;
mod parse_args;
mod preserve_fds;
mod selinux;
mod signal;
mod sudo_edit;
mod tcsetpgrp_nobg;
mod tgetpass;
mod ttyname;
mod utmp;

use common::*;
use hooks::*;
pub use utsudo_util::fluent::*;

/* Initializer for instance index to indicate that debugging is not setup. */
// #define SUDO_DEBUG_INSTANCE_INITIALIZER	-1
pub const SUDO_DEBUG_INSTANCE_INITIALIZER: libc::c_int = -1;

// #define	X_OK	1		/* Test for execute permission.  */
pub const X_OK: libc::c_int = 1;

/* Values of sudo_conf_group_source() */
// #define GROUP_SOURCE_STATIC	1
// #define GROUP_SOURCE_DYNAMIC	2
pub const GROUP_SOURCE_STATIC: libc::c_int = 1;
pub const GROUP_SOURCE_DYNAMIC: libc::c_int = 2;
pub const _SC_NGROUPS_MAX: libc::c_int = 3;

// #define NGROUPS_MAX    65536	/* supplemental group IDs are available */
pub const NGROUPS_MAX: libc::c_int = 65536;

/* Flags for sudo_conf_read() */
// #define SUDO_CONF_PATHS		0x02
// #define SUDO_CONF_SETTINGS	0x08
// #define SUDO_CONF_ALL		0x0f
pub const SUDO_CONF_PATHS: libc::c_int = 0x02;
pub const SUDO_CONF_SETTINGS: libc::c_int = 0x08;
pub const SUDO_CONF_ALL: libc::c_int = 0x0f;

/* We define these the same for all machines.
Changes from this to the outside world should be done in `_exit'.  */
//    #define	EXIT_FAILURE	1	/* Failing exit status.  */
//    #define	EXIT_SUCCESS	0	/* Successful exit status.  */
pub const EXIT_FAILURE: libc::c_int = 1;
pub const EXIT_SUCCESS: libc::c_int = 0;
pub const MODE_VALIDATE_MODE_INVALIDATE: libc::c_int = MODE_VALIDATE | MODE_INVALIDATE;
pub const MODE_CHECK_MODE_INVALIDATE: libc::c_int = MODE_CHECK | MODE_INVALIDATE;
pub const MODE_LIST_MODE_INVALIDATE: libc::c_int = MODE_LIST | MODE_INVALIDATE;

// let sudo_api_mkversion_1_0: libc::c_uint = SUDO_API_MKVERSION!(1, 0);
// let sudo_api_mkversion_1_1: libc::c_uint = SUDO_API_MKVERSION!(1, 1);
pub const sudo_api_mkversion_1_0: libc::c_uint = SUDO_API_MKVERSION!(1, 0);
pub const sudo_api_mkversion_1_1: libc::c_uint = SUDO_API_MKVERSION!(1, 1);

// #define SET_STRING(s, n)                                                   \
// 	if (strncmp(s, info[i], sizeof(s) - 1) == 0 && info[i][sizeof(s) - 1]) \
// 	{                                                                      \
// 		details->n = info[i] + sizeof(s) - 1;                              \
// 		break;                                                             \
// 	}
#[macro_export]
macro_rules! SET_STRING {
    ($s:expr, $details_n:expr, $len:expr, $info_i:expr) => {
        if strncmp(
            $s,
            $info_i,
            (::std::mem::size_of::<[libc::c_char; $len]>() as libc::c_ulong)
                .wrapping_sub(1 as libc::c_int as libc::c_ulong),
        ) == 0
            && *($info_i).offset(
                (::std::mem::size_of::<[libc::c_char; $len]>() as libc::c_ulong)
                    .wrapping_sub(1 as libc::c_int as libc::c_ulong) as isize,
            ) as libc::c_int
                != 0
        {
            $details_n = ($info_i)
                .offset(::std::mem::size_of::<[libc::c_char; $len]>() as libc::c_ulong as isize)
                .offset(-(1 as libc::c_int as isize));
            break;
        }
    };
}

// #define SET_FLAG(s, n)                                                  \
// 	if (strncmp(s, info[i], sizeof(s) - 1) == 0)                        \
// 	{                                                                   \
// 		switch (sudo_strtobool(info[i] + sizeof(s) - 1))                \
// 		{                                                               \
// 		case true:                                                      \
// 			SET(details->flags, n);                                     \
// 			break;                                                      \
// 		case false:                                                     \
// 			CLR(details->flags, n);                                     \
// 			break;                                                      \
// 		default:                                                        \
// 			sudo_debug_printf(SUDO_DEBUG_ERROR,                         \
// 							  "invalid boolean value for %s", info[i]); \
// 			break;                                                      \
// 		}                                                               \
// 		break;                                                          \
// 	}
#[macro_export]
macro_rules! SET_FLAG {
    ($s:expr, $n:expr, $len:expr, $info_i:expr, $details_flags:expr) => {
        if strncmp(
            $s,
            $info_i,
            (::std::mem::size_of::<[libc::c_char; $len]>() as libc::c_ulong)
                .wrapping_sub(1 as libc::c_int as libc::c_ulong),
        ) == 0 as libc::c_int
        {
            match sudo_strtobool_v1(
                ($info_i)
                    .offset(::std::mem::size_of::<[libc::c_char; $len]>() as libc::c_ulong as isize)
                    .offset(-(1 as libc::c_int as isize)),
            ) {
                1 => {
                    SET!($details_flags, $n);
                }
                0 => {
                    CLR!($details_flags, $n);
                }
                _ => {
                    sudo_debug_printf!(
                        SUDO_DEBUG_ERROR,
                        b"invalid boolean value for %s\0" as *const u8 as *const libc::c_char,
                        $info_i
                    );
                }
            } // !match
            break;
        }
    };
}

// #define	_PATH_DEVNULL	"/dev/null"
#[macro_export]
macro_rules! _PATH_DEVNULL {
    () => {
        b"/dev/null\0" as *const u8 as *const libc::c_char
    };
}

/* Define to the full name of this package. */
// #define PACKAGE_NAME "utsudo"
#[macro_export]
macro_rules! PACKAGE_NAME {
    () => {
        b"utsudo\0" as *const u8 as *const libc::c_char
    };
}

#[macro_export]
macro_rules! LOCALEDIR {
    () => {
        b"/usr/share/locale\0" as *const u8 as *const libc::c_char
    };
}

#[macro_export]
macro_rules! CONFIGURE_ARGS {
    () => {
        (b"--build=***64-uos-linux-gnu
        --host=***64-uos-linux-gnu
        --program-prefix=
        --disable-dependency-tracking
        --prefix=/usr
        --exec-prefix=/usr
        --bindir=/usr/bin
        --sbindir=/usr/sbin
        --sysconfdir=/etc
        --datadir=/usr/share
        --includedir=/usr/include
        --libdir=/usr/lib64
        --libexecdir=/usr/libexec
        --localstatedir=/var
        --sharedstatedir=/var/lib
        --mandir=/usr/share/man
        --infodir=/usr/share/info
        --prefix=/usr
        --sbindir=/usr/sbin
        --libdir=/usr/lib64
        --docdir=/usr/share/doc/sudo
        --disable-root-mailer
        --with-logging=syslog
        --with-logfac=authpriv
        --with-pam
        --with-pam-login
        --with-editor=/bin/vi
        --with-env-editor
        --with-ignore-dot
        --with-tty-tickets
        --with-ldap
        --with-ldap-conf-file=/etc/sudo-ldap.conf
        --with-selinux
        --with-passprompt=[utsudo] password for %p:
        --with-linux-audit
        --with-sssd\0" as *const u8 as *const libc::c_char)
    };
}

// # define WCOREDUMP(status)	__WCOREDUMP (status)
/* Nonzero if STATUS indicates the child dumped core.  */
// #define	__WCOREDUMP(status)	((status) & __WCOREFLAG)
// #define	__WCOREFLAG		0x80
#[macro_export]
macro_rules! WCOREDUMP {
    ($status:expr) => {
        (($status) & 0x80)
    };
}

#[link(name = "utsudo_util")]
#[link(name = "util_variadic")]
extern "C" {
    fn umask(__mask: __mode_t) -> __mode_t;
    fn stat(path:*const libc::c_char,buf:*mut stat) -> libc::c_int;
    fn kill(__pid: __pid_t, __sig: libc::c_int) -> libc::c_int;
    fn sigemptyset(__set: *mut sigset_t) -> libc::c_int;
    fn sigprocmask(
        __how: libc::c_int,
        __set: *const sigset_t,
        __oset: *mut sigset_t,
    ) -> libc::c_int;
    fn sigaction(
        __sig: libc::c_int,
        __act: *const sigaction,
        __oact: *mut sigaction,
    ) -> libc::c_int;
    fn printf(_: *const libc::c_char, _: ...) -> libc::c_int;
    fn snprintf(
        _: *mut libc::c_char,
        _: libc::c_ulong,
        _: *const libc::c_char,
        _: ...
    ) -> libc::c_int;
    fn asprintf(__ptr: *mut *mut libc::c_char, __fmt: *const libc::c_char, _: ...) -> libc::c_int;
    fn malloc(_: libc::c_ulong) -> *mut libc::c_void;
    fn reallocarray(__ptr: *mut libc::c_void, __nmemb: size_t, __size: size_t)
        -> *mut libc::c_void;
    fn free(__ptr: *mut libc::c_void);
    fn exit(_: libc::c_int) -> !;
    fn getenv(__name: *const libc::c_char) -> *mut libc::c_char;
    fn memcpy(_: *mut libc::c_void, _: *const libc::c_void, _: libc::c_ulong) -> *mut libc::c_void;
    fn memset(_: *mut libc::c_void, _: libc::c_int, _: libc::c_ulong) -> *mut libc::c_void;
    fn strncmp(_: *const libc::c_char, _: *const libc::c_char, _: libc::c_ulong) -> libc::c_int;
    fn strdup(_: *const libc::c_char) -> *mut libc::c_char;
    fn strchr(_: *const libc::c_char, _: libc::c_int) -> *mut libc::c_char;
    fn strlen(_: *const libc::c_char) -> libc::c_ulong;
    fn access(__name: *const libc::c_char, __type: libc::c_int) -> libc::c_int;
    fn close(__fd: libc::c_int) -> libc::c_int;
    fn getcwd(__buf: *mut libc::c_char, __size: size_t) -> *mut libc::c_char;
    fn dup2(__fd: libc::c_int, __fd2: libc::c_int) -> libc::c_int;
    fn sysconf(__name: libc::c_int) -> libc::c_long;
    fn getpid() -> __pid_t;
    fn getppid() -> __pid_t;
    fn getpgid(__pid: __pid_t) -> __pid_t;
    fn getsid(__pid: __pid_t) -> __pid_t;
    fn getuid() -> __uid_t;
    fn geteuid() -> __uid_t;
    fn getgid() -> __gid_t;
    fn getegid() -> __gid_t;
    fn getgroups(__size: libc::c_int, __list: *mut __gid_t) -> libc::c_int;
    fn setuid(__uid: __uid_t) -> libc::c_int;
    fn setgid(__gid: __gid_t) -> libc::c_int;
    fn setegid(__gid: __gid_t) -> libc::c_int;
    fn tcgetpgrp(__fd: libc::c_int) -> __pid_t;
    fn __errno_location() -> *mut libc::c_int;
    fn fcntl(__fd: libc::c_int, __cmd: libc::c_int, _: ...) -> libc::c_int;
    fn open(__file: *const libc::c_char, __oflag: libc::c_int, _: ...) -> libc::c_int;
    fn getpwuid(__uid: __uid_t) -> *mut passwd;
    fn tzset();
    fn is_selinux_enabled() -> libc::c_int;
    fn sudo_debug_exit_bool_v1(
        func: *const libc::c_char,
        file: *const libc::c_char,
        line: libc::c_int,
        subsys: libc::c_int,
        ret: bool,
    );
    fn sudo_warn_set_conversation_v1(
        conv: Option<
            unsafe extern "C" fn(
                libc::c_int,
                *const sudo_conv_message,
                *mut sudo_conv_reply,
                *mut sudo_conv_callback,
            ) -> libc::c_int,
        >,
    );
    fn sudo_conf_read_v1(conf_file: *const libc::c_char, conf_types: libc::c_int) -> libc::c_int;
    fn sudo_conf_debug_files_v1(progname: *const libc::c_char) -> *mut sudo_conf_debug_file_list;
    fn sudo_conf_disable_coredump_v1() -> bool;
    fn sudo_conf_group_source_v1() -> libc::c_int;
    fn sudo_conf_max_groups_v1() -> libc::c_int;
    fn sudo_debug_get_active_instance_v1() -> libc::c_int;
    fn sudo_debug_printf2_v1(
        func: *const libc::c_char,
        file: *const libc::c_char,
        line: libc::c_int,
        level: libc::c_int,
        fmt: *const libc::c_char,
        _: ...
    );
    fn sudo_debug_register_v1(
        program: *const libc::c_char,
        subsystems: *const *const libc::c_char,
        ids: *mut libc::c_uint,
        debug_files: *mut sudo_conf_debug_file_list,
    ) -> libc::c_int;
    fn sudo_debug_set_active_instance_v1(inst: libc::c_int) -> libc::c_int;
    fn sudo_gethostname_v1() -> *mut libc::c_char;
    fn sudo_parse_gids_v1(
        gidstr: *const libc::c_char,
        basegid: *const gid_t,
        gidsp: *mut *mut gid_t,
    ) -> libc::c_int;
    fn sudo_getgrouplist2_v1(
        name: *const libc::c_char,
        basegid: gid_t,
        groupsp: *mut *mut gid_t,
        ngroupsp: *mut libc::c_int,
    ) -> libc::c_int;
    fn sudo_new_key_val_v1(
        key: *const libc::c_char,
        value: *const libc::c_char,
    ) -> *mut libc::c_char;
    fn initprogname(_: *const libc::c_char);
    fn sudo_setgroups_v1(ngids: libc::c_int, gids: *const gid_t) -> libc::c_int;
    fn sudo_strsplit_v1(
        str: *const libc::c_char,
        endstr: *const libc::c_char,
        sep: *const libc::c_char,
        last: *mut *const libc::c_char,
    ) -> *const libc::c_char;
    fn sudo_strtobool_v1(str: *const libc::c_char) -> libc::c_int;
    fn sudo_strtonum(
        _: *const libc::c_char,
        _: libc::c_longlong,
        _: libc::c_longlong,
        _: *mut *const libc::c_char,
    ) -> libc::c_longlong;
    fn sudo_strtoid_v2(str: *const libc::c_char, errstr: *mut *const libc::c_char) -> id_t;
    fn sudo_strtomode_v1(cp: *const libc::c_char, errstr: *mut *const libc::c_char) -> libc::c_int;
    fn sudo_get_ttysize_v1(rowp: *mut libc::c_int, colp: *mut libc::c_int);
    fn sudo_execute(details: *mut command_details, cstat: *mut command_status) -> libc::c_int;
    fn parse_args(
        argc: libc::c_int,
        argv: *mut *mut libc::c_char,
        nargc: *mut libc::c_int,
        nargv: *mut *mut *mut libc::c_char,
        settingsp: *mut *mut sudo_settings,
        env_addp: *mut *mut *mut libc::c_char,
    ) -> libc::c_int;
    fn sudo_fatalx_nodebug_v1(fmt: *const libc::c_char, _: ...) -> !;
    fn setlocale(__category: libc::c_int, __locale: *const libc::c_char) -> *mut libc::c_char;
    fn sudo_warnx_nodebug_v1(fmt: *const libc::c_char, _: ...);
    fn sudo_warn_nodebug_v1(fmt: *const libc::c_char, _: ...);
    fn sudo_edit(details: *mut command_details) -> libc::c_int;
    fn usage(_: libc::c_int);
    fn deregister_hook(hook: *mut sudo_hook) -> libc::c_int;
    fn getenv_unhooked(name: *const libc::c_char) -> *mut libc::c_char;
    fn get_process_ttyname(name: *mut libc::c_char, namelen: size_t) -> *mut libc::c_char;
    fn textdomain(__domainname: *const libc::c_char) -> *mut libc::c_char;
    fn bindtextdomain(
        __domainname: *const libc::c_char,
        __dirname: *const libc::c_char,
    ) -> *mut libc::c_char;
    fn sudo_fatal_nodebug_v1(fmt: *const libc::c_char, _: ...) -> !;
    fn sudo_pw_dup(pw: *const passwd) -> *mut passwd;
    fn sudo_getprogname() -> *const libc::c_char;
    fn init_signals();
    fn save_signals();
    fn add_preserved_fd(pfds: *mut preserved_fd_list, fd: libc::c_int) -> libc::c_int;
    fn parse_preserved_fds(pfds: *mut preserved_fd_list, fdstr: *const libc::c_char);
    fn disable_coredump();
    fn unlimit_sudo();
    fn sudo_conversation(
        num_msgs: libc::c_int,
        msgs: *const sudo_conv_message,
        replies: *mut sudo_conv_reply,
        callback: *mut sudo_conv_callback,
    ) -> libc::c_int;
    fn sudo_conversation_1_7(
        num_msgs: libc::c_int,
        msgs: *const sudo_conv_message,
        replies: *mut sudo_conv_reply,
    ) -> libc::c_int;
    fn sudo_conversation_printf(
        msg_type: libc::c_int,
        fmt: *const libc::c_char,
        _: ...
    ) -> libc::c_int;
    fn sudo_load_plugins(
        policy_plugin_0: *mut plugin_container,
        io_plugins_0: *mut plugin_container_list,
    ) -> bool;
    static mut sudo_debug_instance: libc::c_int;
}

pub type sudo_gc_types = libc::c_uint;
pub const GC_PTR: sudo_gc_types = 2;
pub const GC_VECTOR: sudo_gc_types = 1;
pub const GC_UNKNOWN: sudo_gc_types = 0;

#[derive(Copy, Clone)]
#[repr(C)]
pub union C2RustUnnamed_13 {
    pub generic: *mut generic_plugin,
    pub policy: *mut policy_plugin,
    pub policy_1_0: *mut policy_plugin_1_0,
    pub io: *mut io_plugin,
    pub io_1_0: *mut io_plugin_1_0,
    pub io_1_1: *mut io_plugin_1_1,
}

#[derive(Copy, Clone)]
#[repr(C)]
pub struct plugin_container {
    pub entries: C2RustUnnamed_14,
    pub debug_files: *mut sudo_conf_debug_file_list,
    pub name: *mut libc::c_char,
    pub path: *mut libc::c_char,
    pub options: *mut *mut libc::c_char,
    pub handle: *mut libc::c_void,
    pub debug_instance: libc::c_int,
    pub u: C2RustUnnamed_13,
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct C2RustUnnamed_14 {
    pub tqe_next: *mut plugin_container,
    pub tqe_prev: *mut *mut plugin_container,
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct plugin_container_list {
    pub tqh_first: *mut plugin_container,
    pub tqh_last: *mut *mut plugin_container,
}
#[no_mangle]
pub static mut policy_plugin: plugin_container = plugin_container {
    entries: C2RustUnnamed_14 {
        tqe_next: 0 as *const plugin_container as *mut plugin_container,
        tqe_prev: 0 as *const *mut plugin_container as *mut *mut plugin_container,
    },
    debug_files: 0 as *const sudo_conf_debug_file_list as *mut sudo_conf_debug_file_list,
    name: 0 as *const libc::c_char as *mut libc::c_char,
    path: 0 as *const libc::c_char as *mut libc::c_char,
    options: 0 as *const *mut libc::c_char as *mut *mut libc::c_char,
    handle: 0 as *const libc::c_void as *mut libc::c_void,
    debug_instance: 0,
    u: C2RustUnnamed_13 {
        generic: 0 as *const generic_plugin as *mut generic_plugin,
    },
};
#[no_mangle]
pub static mut io_plugins: plugin_container_list = plugin_container_list {
    tqh_first: 0 as *const plugin_container as *mut plugin_container,
    tqh_last: 0 as *const *mut plugin_container as *mut *mut plugin_container,
};
#[no_mangle]
pub static mut user_details: user_details = user_details {
    pid: 0,
    ppid: 0,
    pgid: 0,
    tcpgid: 0,
    sid: 0,
    uid: 0,
    euid: 0,
    gid: 0,
    egid: 0,
    username: 0 as *const libc::c_char,
    cwd: 0 as *const libc::c_char,
    tty: 0 as *const libc::c_char,
    host: 0 as *const libc::c_char,
    shell: 0 as *const libc::c_char,
    groups: 0 as *const gid_t as *mut gid_t,
    ngroups: 0,
    ts_rows: 0,
    ts_cols: 0,
};
#[no_mangle]
pub static mut list_user: *const libc::c_char = 0 as *const libc::c_char;

#[no_mangle]
static mut command_details: command_details = command_details {
    uid: 0,
    euid: 0,
    gid: 0,
    egid: 0,
    umask: 0,
    priority: 0,
    timeout: 0,
    ngroups: 0,
    closefrom: 0,
    flags: 0,
    execfd: 0,
    preserved_fds: preserved_fd_list {
        tqh_first: 0 as *const preserved_fd as *mut preserved_fd,
        tqh_last: 0 as *const *mut preserved_fd as *mut *mut preserved_fd,
    },
    pw: 0 as *const passwd as *mut passwd,
    groups: 0 as *const gid_t as *mut gid_t,
    command: 0 as *const libc::c_char,
    cwd: 0 as *const libc::c_char,
    login_class: 0 as *const libc::c_char,
    chroot: 0 as *const libc::c_char,
    selinux_role: 0 as *const libc::c_char,
    selinux_type: 0 as *const libc::c_char,
    utmp_user: 0 as *const libc::c_char,
    tty: 0 as *const libc::c_char,
    argv: 0 as *const *mut libc::c_char as *mut *mut libc::c_char,
    envp: 0 as *const *mut libc::c_char as *mut *mut libc::c_char,
};
static mut sudo_mode: libc::c_int = 0;


fn main_0(
    mut argc: libc::c_int,
    mut argv: *mut *mut libc::c_char,
    mut envp: *mut *mut libc::c_char,
) -> libc::c_int {
    let mut nargc: libc::c_int = 0;
    let mut ok: libc::c_int = 0;
    let mut status: libc::c_int = 0 as libc::c_int;
    let mut nargv: *mut *mut libc::c_char = std::ptr::null_mut::<*mut libc::c_char>();
    let mut env_add: *mut *mut libc::c_char = std::ptr::null_mut::<*mut libc::c_char>();
    let mut user_info: *mut *mut libc::c_char = std::ptr::null_mut::<*mut libc::c_char>();
    let mut command_info: *mut *mut libc::c_char = std::ptr::null_mut::<*mut libc::c_char>();
    let mut argv_out: *mut *mut libc::c_char = std::ptr::null_mut::<*mut libc::c_char>();
    let mut user_env_out: *mut *mut libc::c_char = std::ptr::null_mut::<*mut libc::c_char>();
    let mut settings: *mut sudo_settings = std::ptr::null_mut::<sudo_settings>();
    let mut plugin: *mut plugin_container = std::ptr::null_mut::<plugin_container>();
    let mut next: *mut plugin_container = std::ptr::null_mut::<plugin_container>();
    let mut mask: sigset_t = sigset_t { __val: [0; 16] };
    unsafe {
        debug_decl_vars!(SUDO_DEBUG_MAIN);

        initprogname(if argc > 0 as libc::c_int {
            *argv.offset(0 as libc::c_int as isize)
        } else {
            b"utsudo\0" as *const u8 as *const libc::c_char
        });

        /* Crank resource limits to unlimited. */
        unlimit_sudo();

        /* Make sure fds 0-2 are open and do OS-specific initialization. */
        fix_fds();
        os_init_common(argc, argv, envp);

        setlocale(LC_ALL, b"\0" as *const u8 as *const libc::c_char);
        bindtextdomain(PACKAGE_NAME!(), LOCALEDIR!());
        textdomain(PACKAGE_NAME!());

        tzset();

        /* Initialize the debug subsystem. */
        if sudo_conf_read_v1(std::ptr::null::<libc::c_char>(), SUDO_CONF_DEBUG)
            == -(1 as libc::c_int)
        {
            exit(EXIT_FAILURE);
        }

        sudo_debug_instance = sudo_debug_register_v1(
            sudo_getprogname(),
            std::ptr::null::<*const libc::c_char>(),
            std::ptr::null_mut::<libc::c_uint>(),
            sudo_conf_debug_files_v1(sudo_getprogname()),
        );

        if sudo_debug_instance == SUDO_DEBUG_INSTANCE_ERROR {
            exit(EXIT_FAILURE);
        }

        /* Make sure we are setuid root. */
        sudo_check_suid(if argc > 0 as libc::c_int {
            *argv.offset(0 as libc::c_int as isize)
        } else {
            b"utsudo\0" as *const u8 as *const libc::c_char
        });

        /* Save original signal state and setup default signal handlers. */
        save_signals();
        init_signals();

        /* Reset signal mask to the default value (unblock). */
        sigemptyset(&mut mask);
        sigprocmask(SIG_SETMASK, &mask, std::ptr::null_mut::<sigset_t>());

        /* Parse the rest of sudo.conf. */
        sudo_conf_read_v1(
            std::ptr::null::<libc::c_char>(),
            SUDO_CONF_ALL & !SUDO_CONF_DEBUG,
        );

        /* Fill in user_info with user name, uid, cwd, etc. */
        user_info = get_user_info(&mut user_details);
        if user_info.is_null() {
            exit(EXIT_FAILURE); /* get_user_info printed error message */
        }

        /* Disable core dumps if not enabled in sudo.conf. */
        if sudo_conf_disable_coredump_v1() {
            disable_coredump();
        }

        /* Parse command line arguments. */
        sudo_mode = parse_args(
            argc,
            argv,
            &mut nargc,
            &mut nargv,
            &mut settings,
            &mut env_add,
        );
        sudo_debug_printf!(
            SUDO_DEBUG_DEBUG,
            b"sudo_mode %d\0" as *const u8 as *const libc::c_char,
            sudo_mode
        );

        /* Print sudo version early, in case of plugin init failure. */
        if ISSET!(sudo_mode, MODE_VERSION) != 0 {
            let mut version = translate_two("version", PACKAGE_VERSION!());
            println!("{}", version);

            // printf(
            //    b"Sudo version %s\n\0" as *const u8 as *const libc::c_char,
            //     PACKAGE_VERSION!(),
            //);

            if user_details.uid == ROOT_UID as libc::c_uint {
                printf(
                    b"Configure options: %s\n\0" as *const u8 as *const libc::c_char,
                    CONFIGURE_ARGS!(),
                );
            }
        }

        /* Use conversation function for sudo_(warn|fatal)x? for plugins. */
        sudo_warn_set_conversation_v1(Some(
            sudo_conversation
                as unsafe extern "C" fn(
                    libc::c_int,
                    *const sudo_conv_message,
                    *mut sudo_conv_reply,
                    *mut sudo_conv_callback,
                ) -> libc::c_int,
        ));

        /* Load plugins. */
        if !sudo_load_plugins(&mut policy_plugin, &mut io_plugins) {
            sudo_fatalx!(
                b"fatal error, unable to load plugins\0" as *const u8 as *const libc::c_char,
            );
        }

        /* Open policy plugin. */
        ok = policy_open(
            &mut policy_plugin,
            settings,
            user_info as *const *mut libc::c_char,
            envp as *const *mut libc::c_char,
        );
        if ok != 1 {
            if ok == -(2 as libc::c_int) {
                usage(1);
            } else {
                sudo_fatalx!(
                    b"unable to initialize policy plugin\0" as *const u8 as *const libc::c_char,
                );
            }
        }

        //为了可以中途跳出，加一个循环
        loop {
            match sudo_mode & MODE_MASK {
                MODE_VERSION => {
                    policy_show_version(&mut policy_plugin, (user_details.uid == 0) as libc::c_int);
                    plugin = io_plugins.tqh_first;
                    while !plugin.is_null() {
                        ok = iolog_open(
                            plugin,
                            settings,
                            user_info as *const *mut libc::c_char,
                            std::ptr::null::<*mut libc::c_char>(),
                            nargc,
                            nargv as *const *mut libc::c_char,
                            envp as *const *mut libc::c_char,
                        );
                        if ok != -(1 as libc::c_int) {
                            iolog_show_version(plugin, (user_details.uid == 0) as libc::c_int);
                        }
                        plugin = (*plugin).entries.tqe_next;
                    }
                    break;
                }
                MODE_VALIDATE | MODE_VALIDATE_MODE_INVALIDATE => {
                    ok = policy_validate(&mut policy_plugin);
                    exit((ok != 1 as libc::c_int) as libc::c_int);
                }
                MODE_KILL | MODE_INVALIDATE => {
                    policy_invalidate(&mut policy_plugin, (sudo_mode == MODE_KILL) as libc::c_int);
                    exit(0);
                    break;
                }
                MODE_CHECK | MODE_CHECK_MODE_INVALIDATE | MODE_LIST | MODE_LIST_MODE_INVALIDATE => {
                    ok = policy_list(
                        &mut policy_plugin,
                        nargc,
                        nargv as *const *mut libc::c_char,
                        ISSET!(sudo_mode, MODE_LONG_LIST),
                        list_user,
                    );
                    exit((ok != 1 as libc::c_int) as libc::c_int);
                }
                MODE_EDIT | MODE_RUN => {
                    ok = policy_check(
                        &mut policy_plugin,
                        nargc,
                        nargv as *const *mut libc::c_char,
                        env_add,
                        &mut command_info,
                        &mut argv_out,
                        &mut user_env_out,
                    );

                    sudo_debug_printf!(
                        SUDO_DEBUG_INFO,
                        b"policy plugin returns %d\0" as *const u8 as *const libc::c_char,
                        ok
                    );
                    if ok != 1 {
                        if ok == -(2 as libc::c_int) {
                            usage(1);
                        }
                        exit(EXIT_FAILURE); /* plugin printed error message */
                    }
                    /* Reset nargv/nargc based on argv_out. */
                    /* XXX - leaks old nargv in shell mode */
                    nargv = argv_out;
                    nargc = 0 as libc::c_int;
                    while !(*nargv.offset(nargc as isize)).is_null() {
                        nargc += 1;
                    }
                    if nargc == 0 {
                        sudo_fatalx!(
                            b"plugin did not return a command to execute\0" as *const u8
                                as *const libc::c_char,
                        );
                    }
                    /* Open I/O plugins once policy plugin succeeds. */
                    plugin = io_plugins.tqh_first;
                    while !plugin.is_null() && {
                        next = (*plugin).entries.tqe_next;
                        1 as libc::c_int != 0
                    } {
                        ok = iolog_open(
                            plugin,
                            settings,
                            user_info as *const *mut libc::c_char,
                            command_info as *const *mut libc::c_char,
                            nargc,
                            nargv as *const *mut libc::c_char,
                            user_env_out as *const *mut libc::c_char,
                        );
                        match ok {
                            1 => {}
                            0 => {
                                /* I/O plugin asked to be disabled, remove and free. */
                                iolog_unlink(plugin);
                            }
                            -2 => {
                                usage(1);
                            }
                            _ => {
                                sudo_fatalx!(
                                    b"error initializing I/O plugin %s\0" as *const u8
                                        as *const libc::c_char,
                                    (*plugin).name
                                );
                            }
                        } // ! match ok

                        plugin = next;
                    } // ! while !plugin.is_null()

                    /* Setup command details and run command/edit. */
                    command_info_to_details(
                        command_info as *const *mut libc::c_char,
                        &mut command_details,
                    );
                    command_details.tty = user_details.tty;
                    command_details.argv = argv_out;
                    command_details.envp = user_env_out;
                    if ISSET!(sudo_mode, MODE_LOGIN_SHELL) != 0 {
                        SET!(command_details.flags, CD_LOGIN_SHELL);
                    }

                    if ISSET!(sudo_mode, MODE_BACKGROUND) != 0 {
                        SET!(command_details.flags, CD_BACKGROUND);
                    }
                    /* Become full root (not just setuid) so user cannot kill us. */
                    if setuid(ROOT_UID as __uid_t) == -(1 as libc::c_int) {
                        sudo_warn!(
                            b"setuid(%d)\0" as *const u8 as *const libc::c_char,
                            ROOT_UID
                        );
                    }

                    if ISSET!(command_details.flags, CD_SUDOEDIT) != 0 {
                        status = sudo_edit(&mut command_details);
                    } else {
                        status = run_command(&mut command_details);
                    }

                    /* The close method was called by sudo_edit/run_command. */
                    break;
                }
                _ => {
                    sudo_fatalx!(
                        b"unexpected sudo mode 0x%x\0" as *const u8 as *const libc::c_char,
                        sudo_mode
                    );
                }
            } // ! match  sudo_mode & MODE_MASK
            break;
        } // ! loop

        /*
         * If the command was terminated by a signal, sudo needs to terminated
         * the same way.  Otherwise, the shell may ignore a keyboard-generated
         * signal.  However, we want to avoid having sudo dump core itself.
         */
        if WIFSIGNALED!(status) {
            let mut sa: sigaction = sigaction {
                __sigaction_handler: Signal_handler { sa_handler: None },
                sa_mask: sigset_t { __val: [0; 16] },
                sa_flags: 0,
                sa_restorer: None,
            };
            if WCOREDUMP!(status) != 0 {
                disable_coredump();
            }
            memset(
                &mut sa as *mut sigaction as *mut libc::c_void,
                0 as libc::c_int,
                ::std::mem::size_of::<sigaction>() as libc::c_ulong,
            );
            sigemptyset(&mut sa.sa_mask);
            sa.__sigaction_handler.sa_handler = None;
            sigaction(WTERMSIG!(status), &sa, std::ptr::null_mut::<sigaction>());
            sudo_debug_exit_int_v1(
                get_function_name!(),
                get_file_name!(),
                line!() as libc::c_int,
                sudo_debug_subsys,
                WTERMSIG!(status) | 128,
            );

            kill(getpid(), WTERMSIG!(status));
        }

        sudo_debug_exit_int_v1(
            get_function_name!(),
            get_file_name!(),
            line!() as libc::c_int,
            sudo_debug_subsys,
            WEXITSTATUS!(status),
        );
        exit(WEXITSTATUS!(status));
    }
}

/// # Safety
///
#[no_mangle]
pub unsafe extern "C" fn os_init_common(
    mut _argc: libc::c_int,
    mut _argv: *mut *mut libc::c_char,
    mut _envp: *mut *mut libc::c_char,
) -> libc::c_int {
    gc_init();
    0 as libc::c_int
}

/*
 * Ensure that stdin, stdout and stderr are open; set to /dev/null if not.
 * Some operating systems do this automatically in the kernel or libc.
 */
fn fix_fds() {
    let mut miss: [libc::c_int; 3] = [0; 3];
    let mut devnull: libc::c_int = -(1 as libc::c_int);
    unsafe {
        debug_decl!(SUDO_DEBUG_UTIL);

        /*
         * stdin, stdout and stderr must be open; set them to /dev/null
         * if they are closed.
         */

        miss[STDIN_FILENO as usize] =
            (fcntl(STDIN_FILENO, F_GETFL, 0) == -(1 as libc::c_int)) as libc::c_int;
        miss[STDOUT_FILENO as usize] =
            (fcntl(STDOUT_FILENO, F_GETFL, 0) == -(1 as libc::c_int)) as libc::c_int;
        miss[STDERR_FILENO as usize] =
            (fcntl(STDERR_FILENO, F_GETFL, 0) == -(1 as libc::c_int)) as libc::c_int;
        if miss[STDIN_FILENO as usize] != 0
            || miss[STDOUT_FILENO as usize] != 0
            || miss[STDERR_FILENO as usize] != 0
        {
            devnull = open(
                _PATH_DEVNULL!(),
                O_RDWR,
                S_IRUSR!() | S_IWUSR!() | S_IRGRP!() | S_IROTH!(),
            );

            if devnull == -(1 as libc::c_int) {
                sudo_fatal!(
                    b"unable to open %s\0" as *const u8 as *const libc::c_char,
                    _PATH_DEVNULL!()
                );
            }
            if miss[STDIN_FILENO as usize] != 0
                && dup2(devnull, STDIN_FILENO) == -(1 as libc::c_int)
            {
                sudo_fatal!(b"dup2\0" as *const u8 as *const libc::c_char,);
            }
            if miss[STDOUT_FILENO as usize] != 0
                && dup2(devnull, STDOUT_FILENO) == -(1 as libc::c_int)
            {
                sudo_fatal!(b"dup2\0" as *const u8 as *const libc::c_char,);
            }
            if miss[STDERR_FILENO as usize] != 0
                && dup2(devnull, STDERR_FILENO) == -(1 as libc::c_int)
            {
                sudo_fatal!(b"dup2\0" as *const u8 as *const libc::c_char,);
            }
            if devnull > STDERR_FILENO {
                close(devnull);
            }
        }
        debug_return!();
    } //unsafe
}

/*
 * Allocate space for groups and fill in using sudo_getgrouplist2()
 * for when we cannot (or don't want to) use getgroups().
 * Returns 0 on success and -1 on failure.
 */
fn fill_group_list(mut ud: *mut user_details) -> libc::c_int {
    let mut ret: libc::c_int = -(1 as libc::c_int);
    unsafe {
        debug_decl!(SUDO_DEBUG_UTIL);

        /*
         * If user specified a max number of groups, use it, otherwise let
         * sudo_getgrouplist2() allocate the group vector.
         */
        (*ud).ngroups = sudo_conf_max_groups_v1();

        if (*ud).ngroups > 0 {
            (*ud).groups = reallocarray(
                std::ptr::null_mut::<libc::c_void>(),
                (*ud).ngroups as size_t,
                ::core::mem::size_of::<gid_t>() as libc::c_ulong,
            ) as *mut gid_t;
            if !((*ud).groups).is_null() {
                /* No error on insufficient space if user specified max_groups. */
                sudo_getgrouplist2_v1(
                    (*ud).username,
                    (*ud).gid,
                    &mut (*ud).groups,
                    &mut (*ud).ngroups,
                );
                ret = 0 as libc::c_int;
            }
        } else {
            (*ud).groups = std::ptr::null_mut::<gid_t>();
            ret = sudo_getgrouplist2_v1(
                (*ud).username,
                (*ud).gid,
                &mut (*ud).groups,
                &mut (*ud).ngroups,
            );
        }
        if ret == -(1 as libc::c_int) {
            sudo_debug_printf!(
                SUDO_DEBUG_ERROR | SUDO_DEBUG_ERRNO,
                b"%s: %s: unable to get groups via sudo_getgrouplist2()\0" as *const u8
                    as *const libc::c_char,
                get_function_name!(),
                (*ud).username
            );
        } else {
            sudo_debug_printf!(
                SUDO_DEBUG_INFO,
                b"%s: %s: got %d groups via sudo_getgrouplist2()\0" as *const u8
                    as *const libc::c_char,
                get_function_name!(),
                (*ud).username,
                (*ud).ngroups
            );
        }

        debug_return_int!(ret);
    } //unsafe
}

fn get_user_groups(mut ud: *mut user_details) -> *mut libc::c_char {
    // let mut current_block: u64;
    let mut cp: *mut libc::c_char = std::ptr::null_mut::<libc::c_char>();
    let mut gid_list: *mut libc::c_char = std::ptr::null_mut::<libc::c_char>();
    let mut glsize: size_t = 0;
    let mut i: libc::c_int = 0;
    let mut len: libc::c_int = 0;
    let mut group_source: libc::c_int = 0;
    unsafe {
        debug_decl!(SUDO_DEBUG_UTIL);

        (*ud).groups = std::ptr::null_mut::<gid_t>();
        group_source = sudo_conf_group_source_v1();
        if group_source != GROUP_SOURCE_DYNAMIC {
            let mut maxgroups: libc::c_int = sysconf(_SC_NGROUPS_MAX as libc::c_int) as libc::c_int;

            if maxgroups < 0 {
                maxgroups = NGROUPS_MAX as libc::c_int;
            }
            (*ud).ngroups = getgroups(0, std::ptr::null_mut::<__gid_t>());
            if (*ud).ngroups > 0 {
                /* Use groups from kernel if not too many or source is static. */
                if (*ud).ngroups < maxgroups || group_source == GROUP_SOURCE_STATIC {
                    (*ud).groups = reallocarray(
                        std::ptr::null_mut::<libc::c_void>(),
                        (*ud).ngroups as size_t,
                        ::core::mem::size_of::<gid_t>() as libc::c_ulong,
                    ) as *mut gid_t;
                    if ((*ud).groups).is_null() {
                        debug_return_str!(gid_list as *mut libc::c_char);
                    }

                    if getgroups((*ud).ngroups, (*ud).groups) < 0 {
                        sudo_debug_printf!(
                            SUDO_DEBUG_ERROR | SUDO_DEBUG_ERRNO,
                            b"%s: %s: unable to get %d groups via getgroups()\0" as *const u8
                                as *const libc::c_char,
                            get_function_name!(),
                            (*ud).username,
                            (*ud).ngroups
                        );
                        free((*ud).groups as *mut libc::c_void);
                        (*ud).groups = std::ptr::null_mut::<gid_t>();
                    } else {
                        sudo_debug_printf!(
                            SUDO_DEBUG_INFO,
                            b"%s: %s: got %d groups via getgroups()\0" as *const u8
                                as *const libc::c_char,
                            get_function_name!(),
                            (*ud).username,
                            (*ud).ngroups
                        );
                    }
                }
            }
        }
        if ((*ud).groups).is_null() {
            /*
             * Query group database if kernel list is too small or disabled.
             * Typically, this is because NFS can only support up to 16 groups.
             */
            if fill_group_list(ud) == -(1 as libc::c_int) {
                debug_return_str!(gid_list as *mut libc::c_char);
            }
        }

        /*
         * Format group list as a comma-separated string of gids.
         */
        glsize = (::std::mem::size_of::<[libc::c_char; 8]>() as libc::c_ulong)
            .wrapping_sub(1 as libc::c_int as libc::c_ulong)
            .wrapping_add(((*ud).ngroups * (MAX_UID_T_LEN + 1)) as libc::c_ulong);
        gid_list = malloc(glsize) as *mut libc::c_char;
        if gid_list.is_null() {
            debug_return_str!(gid_list as *mut libc::c_char);
        }
        memcpy(
            gid_list as *mut libc::c_void,
            b"groups=\0" as *const u8 as *const libc::c_char as *const libc::c_void,
            (::core::mem::size_of::<[libc::c_char; 8]>() as libc::c_ulong)
                .wrapping_sub(1 as libc::c_int as libc::c_ulong),
        );
        cp = gid_list
            .offset(::core::mem::size_of::<[libc::c_char; 8]>() as libc::c_ulong as isize)
            .offset(-(1 as libc::c_int as isize));

        i = 0 as libc::c_int;
        while i < (*ud).ngroups {
            len = snprintf(
                cp,
                glsize.wrapping_sub(cp.offset_from(gid_list) as libc::c_long as libc::c_ulong),
                b"%s%u\0" as *const u8 as *const libc::c_char,
                if i != 0 {
                    b",\0" as *const u8 as *const libc::c_char
                } else {
                    b"\0" as *const u8 as *const libc::c_char
                },
                *((*ud).groups).offset(i as isize),
            );
            if len < 0 as libc::c_int
                || len as size_t
                    >= glsize
                        .wrapping_sub(cp.offset_from(gid_list) as libc::c_long as libc::c_ulong)
            {
                sudo_fatalx!(
                    b"internal error, %s overflow\0" as *const u8 as *const libc::c_char,
                    get_function_name!()
                );
            }
            cp = cp.offset(len as isize);
            i += 1;
        }

        //  done:
        debug_return_str!(gid_list as *mut libc::c_char);
    } //unsafe
}

/*
 * Return user information as an array of name=value pairs.
 * and fill in struct user_details (which shares the same strings).
 */
fn get_user_info(mut ud: *mut user_details) -> *mut *mut libc::c_char {
    let mut cp: *mut libc::c_char = std::ptr::null_mut::<libc::c_char>();
    let mut user_info: *mut *mut libc::c_char = std::ptr::null_mut::<*mut libc::c_char>();
    let mut path: [libc::c_char; 4096] = [0; 4096];
    let mut i: libc::c_uint = 0 as libc::c_int as libc::c_uint;
    let mut mask: mode_t = 0;
    let mut pw: *mut passwd = std::ptr::null_mut::<passwd>();
    let mut fd: libc::c_int = 0;
    unsafe {
        debug_decl!(SUDO_DEBUG_UTIL);

        /*
         * On BSD systems you can set a hint to keep the password and
         * group databases open instead of having to open and close
         * them all the time.  Since sudo does a lot of password and
         * group lookups, keeping the file open can speed things up.
         */
        memset(
            ud as *mut libc::c_void,
            0 as libc::c_int,
            ::std::mem::size_of::<user_details>() as libc::c_ulong,
        );

        'oom: loop {
            /* XXX - bound check number of entries */
            user_info = reallocarray(
                std::ptr::null_mut::<libc::c_void>(),
                32 as libc::c_int as size_t,
                ::std::mem::size_of::<*mut libc::c_char>() as libc::c_ulong,
            ) as *mut *mut libc::c_char;

            if user_info.is_null() {
                break 'oom;
            }

            (*ud).pid = getpid();
            (*ud).ppid = getppid();
            (*ud).pgid = getpgid(0 as libc::c_int);
            (*ud).tcpgid = -(1 as libc::c_int);
            fd = open(_PATH_TTY!(), O_RDWR);
            if fd != -(1 as libc::c_int) {
                (*ud).tcpgid = tcgetpgrp(fd);
                close(fd);
            }

            (*ud).sid = getsid(0 as libc::c_int);
            (*ud).uid = getuid();
            (*ud).euid = geteuid();
            (*ud).gid = getgid();
            (*ud).egid = getegid();

            pw = getpwuid((*ud).uid);

            if pw.is_null() {
                sudo_fatalx!(
                    b"you do not exist in the %s database\0" as *const u8 as *const libc::c_char,
                    b"passwd\0" as *const u8 as *const libc::c_char
                );
            }

            let fresh0 = &mut *user_info.offset(i as isize);
            *fresh0 =
                sudo_new_key_val_v1(b"user\0" as *const u8 as *const libc::c_char, (*pw).pw_name);

            if (*user_info.offset(i as isize)).is_null() {
                break 'oom;
            }

            (*ud).username = (*user_info.offset(i as isize))
                .offset(::std::mem::size_of::<[libc::c_char; 6]>() as libc::c_ulong as isize)
                .offset(-(1 as libc::c_int as isize));

            /* Stash user's shell for use with the -s flag; don't pass to plugin. */
            (*ud).shell = getenv(b"SHELL\0" as *const u8 as *const libc::c_char);
            if ((*ud).shell).is_null()
                || *((*ud).shell).offset(0 as libc::c_int as isize) as libc::c_int == '\0' as i32
            {
                (*ud).shell =
                    if *((*pw).pw_shell).offset(0 as libc::c_int as isize) as libc::c_int != 0 {
                        (*pw).pw_shell
                    } else {
                        _PATH_SUDO_BSHELL!()
                    };
            }
            (*ud).shell = strdup((*ud).shell);
            if ((*ud).shell).is_null() {
                break 'oom;
            }

            i = i.wrapping_add(1);
            if asprintf(
                &mut *user_info.offset(i as isize) as *mut *mut libc::c_char,
                b"pid=%d\0" as *const u8 as *const libc::c_char,
                (*ud).pid,
            ) == -(1 as libc::c_int)
            {
                break 'oom;
            }

            i = i.wrapping_add(1);
            if asprintf(
                &mut *user_info.offset(i as isize) as *mut *mut libc::c_char,
                b"ppid=%d\0" as *const u8 as *const libc::c_char,
                (*ud).ppid,
            ) == -(1 as libc::c_int)
            {
                break 'oom;
            }

            i = i.wrapping_add(1);

            if (*ud).pgid != -(1 as libc::c_int)
                && asprintf(
                    &mut *user_info.offset(i as isize) as *mut *mut libc::c_char,
                    b"pgid=%d\0" as *const u8 as *const libc::c_char,
                    (*ud).pgid,
                ) == -(1 as libc::c_int)
            {
                break 'oom;
            }

            /*if (*ud).pgid != -(1 as libc::c_int) {
                if asprintf(
                    &mut *user_info.offset(i as isize) as *mut *mut libc::c_char,
                    b"pgid=%d\0" as *const u8 as *const libc::c_char,
                    (*ud).pgid,
                ) == -(1 as libc::c_int)
                {
                    break 'oom;
                }
            }*/

            if (*ud).tcpgid != -(1 as libc::c_int) {
                i = i.wrapping_add(1);
                if asprintf(
                    &mut *user_info.offset(i as isize) as *mut *mut libc::c_char,
                    b"tcpgid=%d\0" as *const u8 as *const libc::c_char,
                    (*ud).tcpgid,
                ) == -(1 as libc::c_int)
                {
                    break 'oom;
                }
            }

            if (*ud).sid != -(1 as libc::c_int) {
                i = i.wrapping_add(1);
                if asprintf(
                    &mut *user_info.offset(i as isize) as *mut *mut libc::c_char,
                    b"sid=%d\0" as *const u8 as *const libc::c_char,
                    (*ud).sid,
                ) == -(1 as libc::c_int)
                {
                    break 'oom;
                }
            }

            i = i.wrapping_add(1);
            if asprintf(
                &mut *user_info.offset(i as isize) as *mut *mut libc::c_char,
                b"uid=%u\0" as *const u8 as *const libc::c_char,
                (*ud).uid,
            ) == -(1 as libc::c_int)
            {
                break 'oom;
            }

            i = i.wrapping_add(1);
            if asprintf(
                &mut *user_info.offset(i as isize) as *mut *mut libc::c_char,
                b"euid=%u\0" as *const u8 as *const libc::c_char,
                (*ud).euid,
            ) == -(1 as libc::c_int)
            {
                break 'oom;
            }

            i = i.wrapping_add(1);
            if asprintf(
                &mut *user_info.offset(i as isize) as *mut *mut libc::c_char,
                b"gid=%u\0" as *const u8 as *const libc::c_char,
                (*ud).gid,
            ) == -(1 as libc::c_int)
            {
                break 'oom;
            }

            i = i.wrapping_add(1);
            if asprintf(
                &mut *user_info.offset(i as isize) as *mut *mut libc::c_char,
                b"egid=%u\0" as *const u8 as *const libc::c_char,
                (*ud).egid,
            ) == -(1 as libc::c_int)
            {
                break 'oom;
            }
            cp = get_user_groups(ud);
            if cp.is_null() {
                break 'oom;
            }

            i = i.wrapping_add(1);
            let fresh1 = &mut *user_info.offset(i as isize);
            *fresh1 = cp;

            mask = umask(0 as libc::c_int as __mode_t);
            umask(mask);

            i = i.wrapping_add(1);
            if asprintf(
                &mut *user_info.offset(i as isize) as *mut *mut libc::c_char,
                b"umask=0%o\0" as *const u8 as *const libc::c_char,
                mask,
            ) == -(1 as libc::c_int)
            {
                break 'oom;
            }

            if !(getcwd(
                path.as_mut_ptr(),
                ::std::mem::size_of::<[libc::c_char; 4096]>() as libc::c_ulong,
            ))
            .is_null()
            {
                i = i.wrapping_add(1);
                let fresh2 = &mut *user_info.offset(i as isize);
                *fresh2 = sudo_new_key_val_v1(
                    b"cwd\0" as *const u8 as *const libc::c_char,
                    path.as_mut_ptr(),
                );
                if (*user_info.offset(i as isize)).is_null() {
                    break 'oom;
                }

                (*ud).cwd = (*user_info.offset(i as isize))
                    .offset(::std::mem::size_of::<[libc::c_char; 5]>() as libc::c_ulong as isize)
                    .offset(-(1 as libc::c_int as isize));
            }

            if !(get_process_ttyname(
                path.as_mut_ptr(),
                ::core::mem::size_of::<[libc::c_char; 4096]>() as libc::c_ulong,
            ))
            .is_null()
            {
                i = i.wrapping_add(1);
                let fresh3 = &mut *user_info.offset(i as isize);
                *fresh3 = sudo_new_key_val_v1(
                    b"tty\0" as *const u8 as *const libc::c_char,
                    path.as_mut_ptr(),
                );

                if (*user_info.offset(i as isize)).is_null() {
                    break 'oom;
                }
                (*ud).tty = (*user_info.offset(i as isize))
                    .offset(::core::mem::size_of::<[libc::c_char; 5]>() as libc::c_ulong as isize)
                    .offset(-(1 as libc::c_int as isize));
            } else {
                /* tty may not always be present */
                if *__errno_location() != ENOENT {
                    sudo_warn!(b"unable to determine tty\0" as *const u8 as *const libc::c_char,);
                }
            }

            cp = sudo_gethostname_v1();
            i = i.wrapping_add(1);
            let fresh4 = &mut *user_info.offset(i as isize);
            *fresh4 = sudo_new_key_val_v1(
                b"host\0" as *const u8 as *const libc::c_char,
                if !cp.is_null() {
                    cp
                } else {
                    b"localhost\0" as *const u8 as *const libc::c_char
                },
            );
            free(cp as *mut libc::c_void);

            if (*user_info.offset(i as isize)).is_null() {
                break 'oom;
            }

            // ud->host = user_info[i] + sizeof("host=") - 1;

            (*ud).host = (*user_info.offset(i as isize))
                .offset(::core::mem::size_of::<[libc::c_char; 6]>() as libc::c_ulong as isize)
                .offset(-(1 as libc::c_int as isize));

            sudo_get_ttysize_v1(&mut (*ud).ts_rows, &mut (*ud).ts_cols);

            i = i.wrapping_add(1);
            if asprintf(
                &mut *user_info.offset(i as isize) as *mut *mut libc::c_char,
                b"lines=%d\0" as *const u8 as *const libc::c_char,
                (*ud).ts_rows,
            ) == -(1 as libc::c_int)
            {
                break 'oom;
            }

            i = i.wrapping_add(1);
            if asprintf(
                &mut *user_info.offset(i as isize) as *mut *mut libc::c_char,
                b"cols=%d\0" as *const u8 as *const libc::c_char,
                (*ud).ts_cols,
            ) == -(1 as libc::c_int)
            {
                break 'oom;
            }

            // user_info[++i] = NULL;
            i = i.wrapping_add(1);
            let fresh5 = &mut *user_info.offset(i as isize);
            *fresh5 = std::ptr::null_mut::<libc::c_char>();

            /* Add to list of vectors to be garbage collected at exit. */
            if !gc_add(GC_VECTOR, user_info as *mut libc::c_void) {
                // bad:
                loop {
                    let fresh6 = i;
                    i = i.wrapping_sub(1);
                    if fresh6 == 0 {
                        break;
                    }
                    free(*user_info.offset(i as isize) as *mut libc::c_void);
                }
                free(user_info as *mut libc::c_void);
                debug_return_ptr!(std::ptr::null_mut::<*mut libc::c_char>());
            }

            debug_return_ptr!(user_info);

            break 'oom;
        } // ! 'oom loop

        // oom:
        sudo_warnx!(
            b"%s: %s\0" as *const u8 as *const libc::c_char,
            get_function_name!(),
            b"unable to allocate memory\0" as *const u8 as *const libc::c_char
        );

        // bad:
        loop {
            let fresh6 = i;
            i = i.wrapping_sub(1);
            if fresh6 == 0 {
                break;
            }
            free(*user_info.offset(i as isize) as *mut libc::c_void);
        }
        free(user_info as *mut libc::c_void);
        debug_return_ptr!(std::ptr::null_mut::<*mut libc::c_char>())
    } //unsafe
}

/*
 * Convert a command_info array into a command_details structure.
 */
fn command_info_to_details(mut info: *const *mut libc::c_char, mut details: *mut command_details) {
    let mut i: libc::c_int = 0;
    let mut id: id_t = 0;
    let mut cp: *mut libc::c_char = std::ptr::null_mut::<libc::c_char>();
    let mut errstr: *const libc::c_char = std::ptr::null::<libc::c_char>();
    unsafe {
        debug_decl!(SUDO_DEBUG_PCOMM);

        memset(
            details as *mut libc::c_void,
            0,
            ::std::mem::size_of::<command_details>() as libc::c_ulong,
        );
        (*details).closefrom = -(1 as libc::c_int);
        (*details).execfd = -(1 as libc::c_int);
        (*details).flags = CD_SUDOEDIT_CHECKDIR | CD_SET_GROUPS;

        (*details).preserved_fds.tqh_first = std::ptr::null_mut::<preserved_fd>();
        (*details).preserved_fds.tqh_last = &mut (*details).preserved_fds.tqh_first;

        sudo_debug_printf!(
            SUDO_DEBUG_INFO,
            b"command info from plugin:\0" as *const u8 as *const libc::c_char
        );
        i = 0 as libc::c_int;
        while !(*info.offset(i as isize)).is_null() {
            sudo_debug_printf!(
                SUDO_DEBUG_INFO,
                b"    %d: %s\0" as *const u8 as *const libc::c_char,
                i,
                *info.offset(i as isize)
            );

            loop {
                match *(*info.offset(i as isize)).offset(0 as libc::c_int as isize) as u8 as char {
                    'c' => {
                        SET_STRING!(
                            b"chroot=\0" as *const u8 as *const libc::c_char,
                            (*details).chroot,
                            8,
                            *info.offset(i as isize)
                        );
                        SET_STRING!(
                            b"command=\0" as *const u8 as *const libc::c_char,
                            (*details).command,
                            9,
                            *info.offset(i as isize)
                        );
                        SET_STRING!(
                            b"cwd=\0" as *const u8 as *const libc::c_char,
                            (*details).cwd,
                            5,
                            *info.offset(i as isize)
                        );
                        if strncmp(
                            b"closefrom=\0" as *const u8 as *const libc::c_char,
                            *info.offset(i as isize),
                            (::std::mem::size_of::<[libc::c_char; 11]>() as libc::c_ulong)
                                .wrapping_sub(1 as libc::c_int as libc::c_ulong),
                        ) == 0
                        {
                            cp = (*info.offset(i as isize))
                                .offset(
                                    ::std::mem::size_of::<[libc::c_char; 11]>() as libc::c_ulong
                                        as isize,
                                )
                                .offset(-(1 as libc::c_int as isize));
                            (*details).closefrom = sudo_strtonum(
                                cp,
                                0 as libc::c_int as libc::c_longlong,
                                INT_MAX!() as libc::c_int as libc::c_longlong,
                                &mut errstr,
                            ) as libc::c_int;
                            if !errstr.is_null() {
                                sudo_fatalx!(
                                    b"%s: %s\0" as *const u8 as *const libc::c_char,
                                    *info.offset(i as isize),
                                    errstr
                                );
                            }
                        }
                    }
                    'e' => {
                        SET_FLAG!(
                            b"exec_background=\0" as *const u8 as *const libc::c_char,
                            CD_EXEC_BG,
                            17,
                            *info.offset(i as isize),
                            (*details).flags
                        );

                        if strncmp(
                            b"execfd=\0" as *const u8 as *const libc::c_char,
                            *info.offset(i as isize),
                            (::std::mem::size_of::<[libc::c_char; 8]>() as libc::c_ulong)
                                .wrapping_sub(1 as libc::c_int as libc::c_ulong),
                        ) == 0
                        {
                            cp = (*info.offset(i as isize))
                                .offset(::std::mem::size_of::<[libc::c_char; 8]>() as libc::c_ulong
                                    as isize)
                                .offset(-(1 as libc::c_int as isize));
                            (*details).execfd =
                                sudo_strtonum(cp, 0, INT_MAX!(), &mut errstr) as libc::c_int;
                            if !errstr.is_null() {
                                sudo_fatalx!(
                                    b"%s: %s\0" as *const u8 as *const libc::c_char,
                                    *info.offset(i as isize),
                                    errstr
                                );
                            }
                            /* Must keep fd open during exec. */
                            add_preserved_fd(&mut (*details).preserved_fds, (*details).execfd);
                        }
                    }
                    'l' => {
                        SET_STRING!(
                            b"login_class=\0" as *const u8 as *const libc::c_char,
                            (*details).login_class,
                            13,
                            *info.offset(i as isize)
                        );
                    }
                    'n' => {
                        if strncmp(
                            b"nice=\0" as *const u8 as *const libc::c_char,
                            *info.offset(i as isize),
                            (::std::mem::size_of::<[libc::c_char; 6]>() as libc::c_ulong)
                                .wrapping_sub(1 as libc::c_int as libc::c_ulong),
                        ) == 0
                        {
                            cp = (*info.offset(i as isize))
                                .offset(::std::mem::size_of::<[libc::c_char; 6]>() as libc::c_ulong
                                    as isize)
                                .offset(-(1 as libc::c_int as isize));
                            (*details).priority =
                                sudo_strtonum(cp, INT_MIN!(), INT_MAX!(), &mut errstr)
                                    as libc::c_int;
                            if !errstr.is_null() {
                                sudo_fatalx!(
                                    b"%s: %s\0" as *const u8 as *const libc::c_char,
                                    *info.offset(i as isize),
                                    errstr
                                );
                            }

                            SET!((*details).flags, CD_SET_PRIORITY);
                        } else {
                            SET_FLAG!(
                                b"noexec=\0" as *const u8 as *const libc::c_char,
                                CD_NOEXEC,
                                8,
                                *info.offset(i as isize),
                                (*details).flags
                            );
                        }
                    }
                    'p' => {
                        SET_FLAG!(
                            b"preserve_groups=\0" as *const u8 as *const libc::c_char,
                            CD_PRESERVE_GROUPS,
                            17,
                            *info.offset(i as isize),
                            (*details).flags
                        );
                        if strncmp(
                            b"preserve_fds=\0" as *const u8 as *const libc::c_char,
                            *info.offset(i as isize),
                            (::std::mem::size_of::<[libc::c_char; 14]>() as libc::c_ulong)
                                .wrapping_sub(1 as libc::c_int as libc::c_ulong),
                        ) == 0
                        {
                            parse_preserved_fds(
                                &mut (*details).preserved_fds,
                                (*info.offset(i as isize))
                                    .offset(::std::mem::size_of::<[libc::c_char; 14]>()
                                        as libc::c_ulong
                                        as isize)
                                    .offset(-(1 as libc::c_int as isize)),
                            );
                        }
                    }
                    'r' => {
                        if strncmp(
                            b"runas_egid=\0" as *const u8 as *const libc::c_char,
                            *info.offset(i as isize),
                            (::std::mem::size_of::<[libc::c_char; 12]>() as libc::c_ulong)
                                .wrapping_sub(1 as libc::c_int as libc::c_ulong),
                        ) == 0
                        {
                            cp = (*info.offset(i as isize))
                                .offset(
                                    ::std::mem::size_of::<[libc::c_char; 12]>() as libc::c_ulong
                                        as isize,
                                )
                                .offset(-(1 as libc::c_int as isize));
                            id = sudo_strtoid_v2(cp, &mut errstr);
                            if !errstr.is_null() {
                                sudo_fatalx!(
                                    b"%s: %s\0" as *const u8 as *const libc::c_char,
                                    *info.offset(i as isize),
                                    errstr
                                );
                            }
                            (*details).egid = id;
                            SET!((*details).flags, CD_SET_EGID);
                        } else if strncmp(
                            b"runas_euid=\0" as *const u8 as *const libc::c_char,
                            *info.offset(i as isize),
                            (::std::mem::size_of::<[libc::c_char; 12]>() as libc::c_ulong)
                                .wrapping_sub(1 as libc::c_int as libc::c_ulong),
                        ) == 0
                        {
                            cp = (*info.offset(i as isize))
                                .offset(
                                    ::std::mem::size_of::<[libc::c_char; 12]>() as libc::c_ulong
                                        as isize,
                                )
                                .offset(-(1 as libc::c_int as isize));
                            id = sudo_strtoid_v2(cp, &mut errstr);
                            if !errstr.is_null() {
                                sudo_fatalx!(
                                    b"%s: %s\0" as *const u8 as *const libc::c_char,
                                    *info.offset(i as isize),
                                    errstr
                                );
                            }

                            (*details).euid = id;
                            SET!((*details).flags, CD_SET_EUID);
                        } else if strncmp(
                            b"runas_gid=\0" as *const u8 as *const libc::c_char,
                            *info.offset(i as isize),
                            (::std::mem::size_of::<[libc::c_char; 11]>() as libc::c_ulong)
                                .wrapping_sub(1 as libc::c_int as libc::c_ulong),
                        ) == 0
                        {
                            cp = (*info.offset(i as isize))
                                .offset(
                                    ::std::mem::size_of::<[libc::c_char; 11]>() as libc::c_ulong
                                        as isize,
                                )
                                .offset(-(1 as libc::c_int as isize));
                            id = sudo_strtoid_v2(cp, &mut errstr);
                            if !errstr.is_null() {
                                sudo_fatalx!(
                                    b"%s: %s\0" as *const u8 as *const libc::c_char,
                                    *info.offset(i as isize),
                                    errstr
                                );
                            }
                            (*details).gid = id;
                            SET!((*details).flags, CD_SET_GID);
                        } else if strncmp(
                            b"runas_groups=\0" as *const u8 as *const libc::c_char,
                            *info.offset(i as isize),
                            (::std::mem::size_of::<[libc::c_char; 14]>() as libc::c_ulong)
                                .wrapping_sub(1 as libc::c_int as libc::c_ulong),
                        ) == 0
                        {
                            cp = (*info.offset(i as isize))
                                .offset(
                                    ::std::mem::size_of::<[libc::c_char; 14]>() as libc::c_ulong
                                        as isize,
                                )
                                .offset(-(1 as libc::c_int as isize));
                            (*details).ngroups = sudo_parse_gids_v1(
                                cp,
                                std::ptr::null::<gid_t>(),
                                &mut (*details).groups,
                            );
                            /* sudo_parse_gids() will print a warning on error. */
                            if (*details).ngroups == -(1 as libc::c_int) {
                                exit(EXIT_FAILURE); /* XXX */
                            }
                        } else if strncmp(
                            b"runas_uid=\0" as *const u8 as *const libc::c_char,
                            *info.offset(i as isize),
                            (::std::mem::size_of::<[libc::c_char; 11]>() as libc::c_ulong)
                                .wrapping_sub(1 as libc::c_int as libc::c_ulong),
                        ) == 0
                        {
                            cp = (*info.offset(i as isize))
                                .offset(
                                    ::std::mem::size_of::<[libc::c_char; 11]>() as libc::c_ulong
                                        as isize,
                                )
                                .offset(-(1 as libc::c_int as isize));
                            id = sudo_strtoid_v2(cp, &mut errstr);
                            if !errstr.is_null() {
                                sudo_fatalx!(
                                    b"%s: %s\0" as *const u8 as *const libc::c_char,
                                    *info.offset(i as isize),
                                    errstr
                                );
                            }
                            (*details).uid = id;
                            SET!((*details).flags, CD_SET_UID);
                        }
                    }
                    's' => {
                        SET_STRING!(
                            b"selinux_role=\0" as *const u8 as *const libc::c_char,
                            (*details).selinux_role,
                            14,
                            *info.offset(i as isize)
                        );
                        SET_STRING!(
                            b"selinux_type=\0" as *const u8 as *const libc::c_char,
                            (*details).selinux_type,
                            14,
                            *info.offset(i as isize)
                        );
                        SET_FLAG!(
                            b"set_utmp=\0" as *const u8 as *const libc::c_char,
                            CD_SET_UTMP,
                            10,
                            *info.offset(i as isize),
                            (*details).flags
                        );
                    }
                    't' => {
                        if strncmp(
                            b"timeout=\0" as *const u8 as *const libc::c_char,
                            *info.offset(i as isize),
                            (::std::mem::size_of::<[libc::c_char; 9]>() as libc::c_ulong)
                                .wrapping_sub(1 as libc::c_int as libc::c_ulong),
                        ) == 0
                        {
                            cp = (*info.offset(i as isize))
                                .offset(::std::mem::size_of::<[libc::c_char; 9]>() as libc::c_ulong
                                    as isize)
                                .offset(-(1 as libc::c_int as isize));

                            (*details).timeout = sudo_strtonum(
                                cp,
                                0 as libc::c_int as libc::c_longlong,
                                INT_MAX!() as libc::c_int as libc::c_longlong,
                                &mut errstr,
                            ) as libc::c_int;
                            if !errstr.is_null() {
                                sudo_fatalx!(
                                    b"%s: %s\0" as *const u8 as *const libc::c_char,
                                    *info.offset(i as isize),
                                    errstr
                                );
                            }

                            SET!((*details).flags, CD_SET_TIMEOUT);
                        }
                    }
                    'u' => {
                        if strncmp(
                            b"umask=\0" as *const u8 as *const libc::c_char,
                            *info.offset(i as isize),
                            (::std::mem::size_of::<[libc::c_char; 7]>() as libc::c_ulong)
                                .wrapping_sub(1 as libc::c_int as libc::c_ulong),
                        ) == 0
                        {
                            cp = (*info.offset(i as isize))
                                .offset(::std::mem::size_of::<[libc::c_char; 7]>() as libc::c_ulong
                                    as isize)
                                .offset(-(1 as libc::c_int as isize));
                            (*details).umask = sudo_strtomode_v1(cp, &mut errstr) as mode_t;
                            if !errstr.is_null() {
                                sudo_fatalx!(
                                    b"%s: %s\0" as *const u8 as *const libc::c_char,
                                    *info.offset(i as isize),
                                    errstr
                                );
                            }

                            SET!((*details).flags, CD_SET_UMASK);
                        } else {
                            SET_FLAG!(
                                b"umask_override=\0" as *const u8 as *const libc::c_char,
                                CD_OVERRIDE_UMASK,
                                16,
                                *info.offset(i as isize),
                                (*details).flags
                            );
                            SET_FLAG!(
                                b"use_pty=\0" as *const u8 as *const libc::c_char,
                                CD_USE_PTY,
                                9,
                                *info.offset(i as isize),
                                (*details).flags
                            );
                            SET_STRING!(
                                b"utmp_user=\0" as *const u8 as *const libc::c_char,
                                (*details).utmp_user,
                                11,
                                *info.offset(i as isize)
                            );
                            SET_FLAG!(
                                b"utsudoedit=\0" as *const u8 as *const libc::c_char,
                                CD_SUDOEDIT,
                                12,
                                *info.offset(i as isize),
                                (*details).flags
                            );
                            SET_FLAG!(
                                b"utsudoedit_checkdir=\0" as *const u8 as *const libc::c_char,
                                CD_SUDOEDIT_CHECKDIR,
                                21,
                                *info.offset(i as isize),
                                (*details).flags
                            );
                            SET_FLAG!(
                                b"utsudoedit_follow=\0" as *const u8 as *const libc::c_char,
                                CD_SUDOEDIT_FOLLOW,
                                19,
                                *info.offset(i as isize),
                                (*details).flags
                            );
                        }
                    }
                    _ => {}
                } // match
                break;
            }

            i += 1;
        } // ! while !(*info.offset(i as isize)).is_null()

        if ISSET!((*details).flags, CD_SET_EUID) == 0 {
            (*details).euid = (*details).uid;
        }
        if ISSET!((*details).flags, CD_SET_EGID) == 0 {
            (*details).egid = (*details).gid;
        }
        if ISSET!((*details).flags, CD_SET_UMASK) == 0 {
            CLR!((*details).flags, CD_OVERRIDE_UMASK);
        }
        (*details).pw = getpwuid((*details).euid);
        if !((*details).pw).is_null() && {
            (*details).pw = sudo_pw_dup((*details).pw);
            ((*details).pw).is_null()
        } {
            sudo_fatalx!(
                b"%s: %s\0" as *const u8 as *const libc::c_char,
                get_function_name!(),
                b"unable to allocate memory\0" as *const u8 as *const libc::c_char
            );
        }
        if !((*details).selinux_role).is_null() && is_selinux_enabled() > 0 {
            SET!((*details).flags, CD_RBAC_ENABLED);
        }
        debug_return!();
    } //unsafe
}

fn sudo_check_suid(mut sudo: *const libc::c_char) {
    let mut pathbuf: [libc::c_char; 4096] = [0; 4096];
    let mut sb: stat = sb_all_arch;
    let mut qualified: bool = false;
    unsafe {
        debug_decl!(SUDO_DEBUG_PCOMM);

        if geteuid() != ROOT_UID as libc::c_uint {
            /* Search for sudo binary in PATH if not fully qualified. */
            qualified = !(strchr(sudo, '/' as i32)).is_null();
            if !qualified {
                let mut path: *mut libc::c_char =
                    getenv_unhooked(b"PATH\0" as *const u8 as *const libc::c_char);

                if !path.is_null() {
                    let mut cp: *const libc::c_char = std::ptr::null::<libc::c_char>();
                    let mut ep: *const libc::c_char = std::ptr::null::<libc::c_char>();

                    let mut pathend: *const libc::c_char = path.offset(strlen(path) as isize);
                    cp = sudo_strsplit_v1(
                        path,
                        pathend,
                        b":\0" as *const u8 as *const libc::c_char,
                        &mut ep,
                    );
                    while !cp.is_null() {
                        let mut len: libc::c_int = snprintf(
                            pathbuf.as_mut_ptr(),
                            ::std::mem::size_of::<[libc::c_char; 4096]>() as libc::c_ulong,
                            b"%.*s/%s\0" as *const u8 as *const libc::c_char,
                            ep.offset_from(cp) as libc::c_long as libc::c_int,
                            cp,
                            sudo,
                        );
                        if len < 0 as libc::c_int
                            || len as libc::c_long
                                >= ::std::mem::size_of::<[libc::c_char; 4096]>() as libc::c_ulong
                                    as ssize_t
                        {
                            continue;
                        }
                        if access(pathbuf.as_mut_ptr(), X_OK) == 0 {
                            sudo = pathbuf.as_mut_ptr();
                            qualified = true;
                            break;
                        }
                    } // ! while !cp.is_null()
                } // ! if !path.is_null()
            } //  ! if !qualified

            if qualified as libc::c_int != 0 && stat(sudo, &mut sb) == 0 {
                /* Try to determine why sudo was not running as root. */
                if sb.st_uid != ROOT_UID as libc::c_uint
                    || ISSET!(sb.st_mode, S_ISUID as libc::c_uint) == 0
                {
                    sudo_fatalx!(
                        b"%s must be owned by uid %d and have the setuid bit set\0" as *const u8
                            as *const libc::c_char,
                        sudo,
                        ROOT_UID
                    );
                } else {
                    sudo_fatalx!(
                        b"effective uid is not %d, is %s on a file system 
							   with the 'nosuid' option set or an NFS file system without
							    root privileges?\0" as *const u8 as *const libc::c_char,
                        ROOT_UID,
                        sudo
                    );
                }
            } else {
                sudo_fatalx!(
                    b"effective uid is not %d, is sudo installed setuid root?\0" as *const u8
                        as *const libc::c_char,
                    ROOT_UID
                );
            }
        } // ! if geteuid() != ROOT_UID

        debug_return!();
    } //unsafe
}

/// # Safety
///
#[no_mangle]
pub unsafe fn set_user_groups(mut details: *mut command_details) -> bool {
    let mut ret: bool = false;
    //unsafe {
    debug_decl!(SUDO_DEBUG_EXEC);

    'done: loop {
        if ISSET!((*details).flags, CD_PRESERVE_GROUPS) == 0
            && (*details).ngroups >= 0
            && sudo_setgroups_v1((*details).ngroups, (*details).groups) < 0
        {
            sudo_warn!(
                b"unable to set supplementary group IDs\0" as *const u8 as *const libc::c_char,
            );
            break 'done;
        }

        /*if ISSET!((*details).flags, CD_PRESERVE_GROUPS) == 0 {
            if (*details).ngroups >= 0 && sudo_setgroups_v1((*details).ngroups, (*details).groups) < 0 {
                sudo_warn!(
                    b"unable to set supplementary group IDs\0" as *const u8
                        as *const libc::c_char,
                );
                break 'done;
            }

            /*if (*details).ngroups >= 0 {
                if sudo_setgroups_v1((*details).ngroups, (*details).groups) < 0 {
                    sudo_warn!(
                        b"unable to set supplementary group IDs\0" as *const u8
                            as *const libc::c_char,
                    );
                    break 'done;
                }
            }*/
        }*/

        if ISSET!((*details).flags, CD_SET_EGID) != 0 && setegid((*details).egid) != 0 {
            sudo_warn!(
                b"unable to set effective gid to runas gid %u\0" as *const u8
                    as *const libc::c_char,
                (*details).egid
            );
            break 'done;
        }
        if ISSET!((*details).flags, CD_SET_GID) != 0 && setgid((*details).gid) != 0 {
            sudo_warn!(
                b"unable to set gid to runas gid %u\0" as *const u8 as *const libc::c_char,
                (*details).gid
            );
            break 'done;
        }
        ret = true;

        break 'done;
    } // ! 'done loop

    // done:
    CLR!((*details).flags, CD_SET_GROUPS);
    debug_return_bool!(ret)
    //} //unsafe
}

/*
 * Run the command and wait for it to complete.
 * Returns wait status suitable for use with the wait(2) macros.
 */
/// # Safety
///
#[no_mangle]
pub unsafe fn run_command(mut details: *mut command_details) -> libc::c_int {
    let mut plugin: *mut plugin_container = std::ptr::null_mut::<plugin_container>();
    let mut cstat: command_status = command_status { type_0: 0, val: 0 };
    let mut status: libc::c_int = W_EXITCODE!(1, 0);
    //unsafe {
    debug_decl!(SUDO_DEBUG_EXEC);

    cstat.type_0 = 0 as libc::c_int;
    cstat.val = 0 as libc::c_int;
    sudo_execute(details, &mut cstat);

    match cstat.type_0 {
        CMD_ERRNO => {
            /* exec_setup() or execve() returned an error. */
            sudo_debug_printf!(
                SUDO_DEBUG_DEBUG,
                b"calling policy close with errno %d\0" as *const u8 as *const libc::c_char,
                cstat.val
            );

            policy_close(&mut policy_plugin, 0 as libc::c_int, cstat.val);
            plugin = io_plugins.tqh_first;
            while !plugin.is_null() {
                sudo_debug_printf!(
                    SUDO_DEBUG_DEBUG,
                    b"calling I/O close with errno %d\0" as *const u8 as *const libc::c_char,
                    cstat.val
                );

                iolog_close(plugin, 0 as libc::c_int, cstat.val);
                plugin = (*plugin).entries.tqe_next;
            }
        }
        CMD_WSTATUS => {
            /* Command ran, exited or was killed. */
            status = cstat.val;
            sudo_debug_printf!(
                SUDO_DEBUG_DEBUG,
                b"calling policy close with wait status %d\0" as *const u8 as *const libc::c_char,
                status
            );
            policy_close(&mut policy_plugin, status, 0 as libc::c_int);
            plugin = io_plugins.tqh_first;
            while !plugin.is_null() {
                sudo_debug_printf!(
                    SUDO_DEBUG_DEBUG,
                    b"calling I/O close with wait status %d\0" as *const u8 as *const libc::c_char,
                    status
                );
                iolog_close(plugin, status, 0 as libc::c_int);
                plugin = (*plugin).entries.tqe_next;
            }
        }
        _ => {
            sudo_warnx!(
                b"unexpected child termination condition: %d\0" as *const u8 as *const libc::c_char,
                cstat.type_0
            );
        }
    } // match cstat.type_0

    debug_return_int!(status);
    //} //unsafe
}

/*
 * Format struct sudo_settings as name=value pairs for the plugin
 * to consume.  Returns a NULL-terminated plugin-style array of pairs.
 */
fn format_plugin_settings(
    mut plugin: *mut plugin_container,
    mut sudo_settings: *mut sudo_settings,
) -> *mut *mut libc::c_char {
    // let mut current_block: u64;
    let mut plugin_settings_size: size_t = 0;
    let mut debug_file: *mut sudo_debug_file = std::ptr::null_mut::<sudo_debug_file>();
    let mut setting: *mut sudo_settings = std::ptr::null_mut::<sudo_settings>();
    let mut plugin_settings: *mut *mut libc::c_char = std::ptr::null_mut::<*mut libc::c_char>();
    let mut i: libc::c_uint = 0 as libc::c_int as libc::c_uint;
    unsafe {
        debug_decl!(SUDO_DEBUG_PCOMM);

        /* Determine sudo_settings array size (including plugin_path and NULL) */
        plugin_settings_size = 2 as libc::c_int as size_t;
        setting = sudo_settings;
        while !((*setting).name).is_null() {
            plugin_settings_size = plugin_settings_size.wrapping_add(1);
            setting = setting.offset(1);
        }

        if !((*plugin).debug_files).is_null() {
            debug_file = (*(*plugin).debug_files).tqh_first;
            while !debug_file.is_null() {
                plugin_settings_size = plugin_settings_size.wrapping_add(1);
                debug_file = (*debug_file).entries.tqe_next;
            }
        }

        'bad: loop {
            /* Allocate and fill in. */
            plugin_settings = reallocarray(
                std::ptr::null_mut::<libc::c_void>(),
                plugin_settings_size,
                ::std::mem::size_of::<*mut libc::c_char>() as libc::c_ulong,
            ) as *mut *mut libc::c_char;

            if plugin_settings.is_null() {
                break 'bad;
            }

            let fresh7 = &mut *plugin_settings.offset(i as isize);
            *fresh7 = sudo_new_key_val_v1(
                b"plugin_path\0" as *const u8 as *const libc::c_char,
                (*plugin).path,
            );

            if (*plugin_settings.offset(i as isize)).is_null() {
                break 'bad;
            }
            setting = sudo_settings;

            loop {
                if ((*setting).name).is_null() {
                    break;
                }

                if !((*setting).value).is_null() {
                    sudo_debug_printf!(
                        SUDO_DEBUG_INFO,
                        b"settings: %s=%s\0" as *const u8 as *const libc::c_char,
                        (*setting).name,
                        (*setting).value
                    );

                    i = i.wrapping_add(1);
                    let fresh8 = &mut *plugin_settings.offset(i as isize);
                    *fresh8 = sudo_new_key_val_v1((*setting).name, (*setting).value);

                    if (*plugin_settings.offset(i as isize)).is_null() {
                        break 'bad;
                    }
                }
                setting = setting.offset(1);
            } // ! loop

            if !((*plugin).debug_files).is_null() {
                debug_file = (*(*plugin).debug_files).tqh_first;
                loop {
                    if debug_file.is_null() {
                        break;
                    }
                    i = i.wrapping_add(1);
                    /* XXX - quote filename? */
                    if asprintf(
                        &mut *plugin_settings.offset(i as isize) as *mut *mut libc::c_char,
                        b"debug_flags=%s %s\0" as *const u8 as *const libc::c_char,
                        (*debug_file).debug_file,
                        (*debug_file).debug_flags,
                    ) == -(1 as libc::c_int)
                    {
                        break 'bad;
                    }
                    debug_file = (*debug_file).entries.tqe_next;
                } // ! loop
            }

            i = i.wrapping_add(1);
            let fresh9 = &mut *plugin_settings.offset(i as isize);
            *fresh9 = std::ptr::null_mut::<libc::c_char>();

            /* Add to list of vectors to be garbage collected at exit. */
            if !gc_add(GC_VECTOR, plugin_settings as *mut libc::c_void) {
                sudo_fatalx!(
                    b"%s: %s\0" as *const u8 as *const libc::c_char,
                    get_function_name!(),
                    b"unable to allocate memory\0" as *const u8 as *const libc::c_char
                );
            }

            debug_return_ptr!(plugin_settings);

            break 'bad;
        } // ’bad loop

        // bad:
        loop {
            let fresh10 = i;
            i = i.wrapping_sub(1);
            if fresh10 == 0 {
                break;
            }
            free(*plugin_settings.offset(i as isize) as *mut libc::c_void);
        }
        free(plugin_settings as *mut libc::c_void);
        debug_return_ptr!(std::ptr::null_mut::<*mut libc::c_char>());
    } //unsafe
}

unsafe extern "C" fn policy_open(
    mut plugin: *mut plugin_container,
    mut settings: *mut sudo_settings,
    mut user_info: *const *mut libc::c_char,
    mut user_env: *const *mut libc::c_char,
) -> libc::c_int {
    let mut plugin_settings: *mut *mut libc::c_char = std::ptr::null_mut::<*mut libc::c_char>();
    let mut ret: libc::c_int = 0;
    debug_decl!(SUDO_DEBUG_PCOMM);

    /* Convert struct sudo_settings to plugin_settings[] */
    plugin_settings = format_plugin_settings(plugin, settings);
    if plugin_settings.is_null() {
        sudo_warnx!(
            b"%s: %s\0" as *const u8 as *const libc::c_char,
            get_function_name!(),
            b"unable to allocate memory\0" as *const u8 as *const libc::c_char
        );
        debug_return_int!(-1);
    }

    /*
     * Backwards compatibility for older API versions
     */

    sudo_debug_set_active_instance_v1(SUDO_DEBUG_INSTANCE_INITIALIZER);
    match (*(*plugin).u.generic).version {
        sudo_api_mkversion_1_0 | sudo_api_mkversion_1_1 => {
            ret = ((*(*plugin).u.policy_1_0).open).expect("non-null function pointer")(
                (*(*plugin).u.io_1_0).version,
                Some(
                    sudo_conversation_1_7
                        as unsafe extern "C" fn(
                            libc::c_int,
                            *const sudo_conv_message,
                            *mut sudo_conv_reply,
                        ) -> libc::c_int,
                ),
                Some(
                    sudo_conversation_printf
                        as unsafe extern "C" fn(
                            libc::c_int,
                            *const libc::c_char,
                            ...
                        ) -> libc::c_int,
                ),
                plugin_settings as *const *mut libc::c_char,
                user_info,
                user_env,
            );
        }
        _ => {
            ret = ((*(*plugin).u.policy).open).expect("non-null function pointer")(
                SUDO_API_VERSION!() as libc::c_uint,
                Some(
                    sudo_conversation
                        as unsafe extern "C" fn(
                            libc::c_int,
                            *const sudo_conv_message,
                            *mut sudo_conv_reply,
                            *mut sudo_conv_callback,
                        ) -> libc::c_int,
                ),
                Some(
                    sudo_conversation_printf
                        as unsafe extern "C" fn(
                            libc::c_int,
                            *const libc::c_char,
                            ...
                        ) -> libc::c_int,
                ),
                plugin_settings as *const *mut libc::c_char,
                user_info,
                user_env,
                (*plugin).options as *const *mut libc::c_char,
            );
        }
    } // ! match

    /* Stash plugin debug instance ID if set in open() function. */
    (*plugin).debug_instance = sudo_debug_get_active_instance_v1();
    sudo_debug_set_active_instance_v1(sudo_debug_instance);

    debug_return_int!(ret);
}

unsafe extern "C" fn policy_close(
    mut plugin: *mut plugin_container,
    mut exit_status: libc::c_int,
    mut error_code: libc::c_int,
) {
    debug_decl!(SUDO_DEBUG_PCOMM);

    if ((*(*plugin).u.policy).close).is_some() {
        sudo_debug_set_active_instance_v1((*plugin).debug_instance);
        ((*(*plugin).u.policy).close).expect("non-null function pointer")(exit_status, error_code);
        sudo_debug_set_active_instance_v1(sudo_debug_instance);
    } else if error_code != 0 {
        *__errno_location() = error_code;
        sudo_warn!(
            b"unable to execute %s\0" as *const u8 as *const libc::c_char,
            command_details.command
        );
    }
    debug_return!();
}

unsafe extern "C" fn policy_show_version(
    mut plugin: *mut plugin_container,
    mut verbose: libc::c_int,
) -> libc::c_int {
    let mut ret: libc::c_int = 0;
    debug_decl!(SUDO_DEBUG_PCOMM);

    if ((*(*plugin).u.policy).show_version).is_none() {
        debug_return_int!(true as libc::c_int);
    }
    sudo_debug_set_active_instance_v1((*plugin).debug_instance);
    ret = ((*(*plugin).u.policy).show_version).expect("non-null function pointer")(verbose);
    sudo_debug_set_active_instance_v1(sudo_debug_instance);

    debug_return_int!(ret);
}

unsafe extern "C" fn policy_check(
    mut plugin: *mut plugin_container,
    mut argc: libc::c_int,
    mut argv: *const *mut libc::c_char,
    mut env_add: *mut *mut libc::c_char,
    mut command_info: *mut *mut *mut libc::c_char,
    mut argv_out: *mut *mut *mut libc::c_char,
    mut user_env_out: *mut *mut *mut libc::c_char,
) -> libc::c_int {
    let mut ret: libc::c_int = 0;
    debug_decl!(SUDO_DEBUG_PCOMM);

    if ((*(*plugin).u.policy).check_policy).is_none() {
        sudo_fatalx!(
            b"policy plugin %s is missing the `check_policy' method\0" as *const u8
                as *const libc::c_char,
            (*plugin).name,
        );
    }
    sudo_debug_set_active_instance_v1((*plugin).debug_instance);
    ret = ((*(*plugin).u.policy).check_policy).expect("non-null function pointer")(
        argc,
        argv,
        env_add,
        command_info,
        argv_out,
        user_env_out,
    );
    sudo_debug_set_active_instance_v1(sudo_debug_instance);
    debug_return_int!(ret);
}

unsafe extern "C" fn policy_list(
    mut plugin: *mut plugin_container,
    mut argc: libc::c_int,
    mut argv: *const *mut libc::c_char,
    mut verbose: libc::c_int,
    mut list_user_0: *const libc::c_char,
) -> libc::c_int {
    let mut ret: libc::c_int = 0;
    debug_decl!(SUDO_DEBUG_PCOMM);

    if ((*(*plugin).u.policy).list).is_none() {
        sudo_warnx!(
            b"policy plugin %s does not support listing privileges\0" as *const u8
                as *const libc::c_char,
            (*plugin).name,
        );
        debug_return_int!(false as libc::c_int);
    }
    sudo_debug_set_active_instance_v1((*plugin).debug_instance);
    ret = ((*(*plugin).u.policy).list).expect("non-null function pointer")(
        argc,
        argv,
        verbose,
        list_user_0,
    );
    sudo_debug_set_active_instance_v1(sudo_debug_instance);

    debug_return_int!(ret);
}

unsafe extern "C" fn policy_validate(mut plugin: *mut plugin_container) -> libc::c_int {
    let mut ret: libc::c_int = 0;
    debug_decl!(SUDO_DEBUG_PCOMM);

    if ((*(*plugin).u.policy).validate).is_none() {
        sudo_warnx!(
            b"policy plugin %s does not support the -v option\0" as *const u8
                as *const libc::c_char,
            (*plugin).name
        );
        debug_return_int!(false as libc::c_int);
    }
    sudo_debug_set_active_instance_v1((*plugin).debug_instance);
    ret = ((*(*plugin).u.policy).validate).expect("non-null function pointer")();
    sudo_debug_set_active_instance_v1(sudo_debug_instance);

    debug_return_int!(ret);
}
unsafe extern "C" fn policy_invalidate(mut plugin: *mut plugin_container, mut remove: libc::c_int) {
    debug_decl!(SUDO_DEBUG_PCOMM);
    if ((*(*plugin).u.policy).invalidate).is_none() {
        sudo_fatalx!(
            b"policy plugin %s does not support the -k/-K options\0" as *const u8
                as *const libc::c_char,
            (*plugin).name
        );
    }
    sudo_debug_set_active_instance_v1((*plugin).debug_instance);
    ((*(*plugin).u.policy).invalidate).expect("non-null function pointer")(remove);
    sudo_debug_set_active_instance_v1(sudo_debug_instance);

    debug_return!();
}
/// # Safety
///
#[no_mangle]
pub unsafe extern "C" fn policy_init_session(mut details: *mut command_details) -> libc::c_int {
    let mut ret: libc::c_int = 0;
    debug_decl!(SUDO_DEBUG_PCOMM);

    'done: loop {
        /*
         * We set groups, including supplementary group vector,
         * as part of the session setup.  This allows for dynamic
         * groups to be set via pam_group(8) in pam_setcred(3).
         */
        if ISSET!((*details).flags, CD_SET_GROUPS) != 0 {
            /* set_user_groups() prints error message on failure. */
            if !set_user_groups(details) {
                break 'done;
            }
        }
        /* Session setup may override sudoers umask so set it first. */
        if ISSET!((*details).flags, CD_SET_UMASK) != 0 {
            umask((*details).umask);
        }

        if ((*policy_plugin.u.policy).init_session).is_some() {
            /*
             * Backwards compatibility for older API versions
             */
            sudo_debug_set_active_instance_v1(policy_plugin.debug_instance);

            match (*policy_plugin.u.generic).version {
                sudo_api_mkversion_1_0 | sudo_api_mkversion_1_1 => {
                    ret = ((*policy_plugin.u.policy_1_0).init_session)
                        .expect("non-null function pointer")(
                        (*details).pw
                    );
                }
                _ => {
                    ret = ((*policy_plugin.u.policy).init_session)
                        .expect("non-null function pointer")(
                        (*details).pw, &mut (*details).envp
                    );
                }
            }
            sudo_debug_set_active_instance_v1(sudo_debug_instance);
        }
        break 'done;
    } // 'done loop

    // done:
    debug_return_int!(ret);
}

unsafe extern "C" fn iolog_open(
    mut plugin: *mut plugin_container,
    mut settings: *mut sudo_settings,
    mut user_info: *const *mut libc::c_char,
    mut command_info: *const *mut libc::c_char,
    mut argc: libc::c_int,
    mut argv: *const *mut libc::c_char,
    mut user_env: *const *mut libc::c_char,
) -> libc::c_int {
    let mut plugin_settings: *mut *mut libc::c_char = std::ptr::null_mut::<*mut libc::c_char>();
    let mut ret: libc::c_int = 0;
    debug_decl!(SUDO_DEBUG_PCOMM);

    /* Convert struct sudo_settings to plugin_settings[] */
    plugin_settings = format_plugin_settings(plugin, settings);
    if plugin_settings.is_null() {
        sudo_warnx!(
            b"%s: %s\0" as *const u8 as *const libc::c_char,
            get_function_name!(),
            b"unable to allocate memory\0" as *const u8 as *const libc::c_char
        );
        debug_return_int!(-(1 as libc::c_int));
    }

    /*
     * Backwards compatibility for older API versions
     */
    sudo_debug_set_active_instance_v1((*plugin).debug_instance);
    match (*(*plugin).u.generic).version {
        sudo_api_mkversion_1_0 => {
            ret = ((*(*plugin).u.io_1_0).open).expect("non-null function pointer")(
                (*(*plugin).u.io_1_0).version,
                Some(
                    sudo_conversation_1_7
                        as unsafe extern "C" fn(
                            libc::c_int,
                            *const sudo_conv_message,
                            *mut sudo_conv_reply,
                        ) -> libc::c_int,
                ),
                Some(
                    sudo_conversation_printf
                        as unsafe extern "C" fn(
                            libc::c_int,
                            *const libc::c_char,
                            ...
                        ) -> libc::c_int,
                ),
                plugin_settings as *const *mut libc::c_char,
                user_info,
                argc,
                argv,
                user_env,
            );
        }
        sudo_api_mkversion_1_1 => {
            ret = ((*(*plugin).u.io_1_1).open).expect("non-null function pointer")(
                (*(*plugin).u.io_1_1).version,
                Some(
                    sudo_conversation_1_7
                        as unsafe extern "C" fn(
                            libc::c_int,
                            *const sudo_conv_message,
                            *mut sudo_conv_reply,
                        ) -> libc::c_int,
                ),
                Some(
                    sudo_conversation_printf
                        as unsafe extern "C" fn(
                            libc::c_int,
                            *const libc::c_char,
                            ...
                        ) -> libc::c_int,
                ),
                plugin_settings as *const *mut libc::c_char,
                user_info,
                command_info,
                argc,
                argv,
                user_env,
            );
        }
        _ => {
            ret = ((*(*plugin).u.io).open).expect("non-null function pointer")(
                SUDO_API_VERSION!() as libc::c_uint,
                Some(
                    sudo_conversation
                        as unsafe extern "C" fn(
                            libc::c_int,
                            *const sudo_conv_message,
                            *mut sudo_conv_reply,
                            *mut sudo_conv_callback,
                        ) -> libc::c_int,
                ),
                Some(
                    sudo_conversation_printf
                        as unsafe extern "C" fn(
                            libc::c_int,
                            *const libc::c_char,
                            ...
                        ) -> libc::c_int,
                ),
                plugin_settings as *const *mut libc::c_char,
                user_info,
                command_info,
                argc,
                argv,
                user_env,
                (*plugin).options as *const *mut libc::c_char,
            );
        }
    } // !  match (*(*plugin).u.generic).version

    /* Stash plugin debug instance ID if set in open() function. */
    (*plugin).debug_instance = sudo_debug_get_active_instance_v1();
    sudo_debug_set_active_instance_v1(sudo_debug_instance);

    debug_return_int!(ret);
}
unsafe extern "C" fn iolog_close(
    mut plugin: *mut plugin_container,
    mut exit_status: libc::c_int,
    mut error_code: libc::c_int,
) {
    debug_decl!(SUDO_DEBUG_PCOMM);

    if ((*(*plugin).u.io).close).is_some() {
        sudo_debug_set_active_instance_v1((*plugin).debug_instance);
        ((*(*plugin).u.io).close).expect("non-null function pointer")(exit_status, error_code);
        sudo_debug_set_active_instance_v1(sudo_debug_instance);
    }
    debug_return!();
}

unsafe extern "C" fn iolog_show_version(
    mut plugin: *mut plugin_container,
    mut verbose: libc::c_int,
) -> libc::c_int {
    let mut ret: libc::c_int = 0;
    debug_decl!(SUDO_DEBUG_PCOMM);

    if ((*(*plugin).u.io).show_version).is_none() {
        debug_return_int!(true as libc::c_int);
    }
    sudo_debug_set_active_instance_v1((*plugin).debug_instance);
    ret = ((*(*plugin).u.io).show_version).expect("non-null function pointer")(verbose);
    sudo_debug_set_active_instance_v1(sudo_debug_instance);

    debug_return_int!(ret);
}

/*
 * Remove the specified I/O logging plugin from the io_plugins list.
 * Deregisters any hooks before unlinking, then frees the container.
 */
unsafe extern "C" fn iolog_unlink(mut plugin: *mut plugin_container) {
    debug_decl!(SUDO_DEBUG_PCOMM);

    /* Deregister hooks, if any. */
    if (*(*plugin).u.io).version >= SUDO_API_MKVERSION!(1, 2) as libc::c_uint
        && ((*(*plugin).u.io).deregister_hooks).is_some()
    {
        sudo_debug_set_active_instance_v1((*plugin).debug_instance);
        ((*(*plugin).u.io).deregister_hooks).expect("non-null function pointer")(
            SUDO_HOOK_VERSION!() as libc::c_int,
            Some(deregister_hook as unsafe extern "C" fn(*mut sudo_hook) -> libc::c_int),
        );
        sudo_debug_set_active_instance_v1(sudo_debug_instance);
    }

    /*if (*(*plugin).u.io).version >= SUDO_API_MKVERSION!(1, 2) as libc::c_uint {
        if ((*(*plugin).u.io).deregister_hooks).is_some() {
            sudo_debug_set_active_instance_v1((*plugin).debug_instance);
            ((*(*plugin).u.io).deregister_hooks).expect("non-null function pointer")(
                SUDO_HOOK_VERSION!() as libc::c_int,
                Some(deregister_hook as unsafe extern "C" fn(*mut sudo_hook) -> libc::c_int),
            );
            sudo_debug_set_active_instance_v1(sudo_debug_instance);
        }
    }*/

    /* Remove from io_plugins list and free. */
    if !((*plugin).entries.tqe_next).is_null() {
        (*(*plugin).entries.tqe_next).entries.tqe_prev = (*plugin).entries.tqe_prev;
    } else {
        io_plugins.tqh_last = (*plugin).entries.tqe_prev;
    }
    *(*plugin).entries.tqe_prev = (*plugin).entries.tqe_next;
    free_plugin_container(plugin, 1 as libc::c_int != 0);

    debug_return!();
}

unsafe extern "C" fn free_plugin_container(mut plugin: *mut plugin_container, mut ioplugin: bool) {
    debug_decl!(SUDO_DEBUG_PLUGIN);
    free((*plugin).path as *mut libc::c_void);
    free((*plugin).name as *mut libc::c_void);
    if !((*plugin).options).is_null() {
        let mut i: libc::c_int = 0 as libc::c_int;
        while !(*((*plugin).options).offset(i as isize)).is_null() {
            let fresh11 = i;
            i += 1;
            free(*((*plugin).options).offset(fresh11 as isize) as *mut libc::c_void);
        }
        free((*plugin).options as *mut libc::c_void);
    }

    if ioplugin {
        free(plugin as *mut libc::c_void);
    }

    debug_return!();
}

/// # Safety
///
#[no_mangle]
pub unsafe extern "C" fn gc_add(mut _type_0: sudo_gc_types, mut _v: *mut libc::c_void) -> bool {
    1 as libc::c_int != 0
}

unsafe extern "C" fn gc_init() {}

pub fn main() {
    let mut args: Vec<*mut libc::c_char> = Vec::new();
    for arg in ::std::env::args() {
        args.push(
            (::std::ffi::CString::new(arg))
                .expect("Failed to convert argument into CString.")
                .into_raw(),
        );
    }
    args.push(::core::ptr::null_mut());
    let mut vars: Vec<*mut libc::c_char> = Vec::new();
    for (var_name, var_value) in ::std::env::vars() {
        let var: String = format!("{}={}", var_name, var_value);
        vars.push(
            (::std::ffi::CString::new(var))
                .expect("Failed to convert environment variable into CString.")
                .into_raw(),
        );
    }
    vars.push(::core::ptr::null_mut());

    ::std::process::exit(main_0(
        (args.len() - 1) as libc::c_int,
        args.as_mut_ptr(),
        vars.as_mut_ptr(),
    ) as i32)
}

unsafe extern "C" fn run_static_initializers() {
    io_plugins = {
        plugin_container_list {
            tqh_first: std::ptr::null_mut::<plugin_container>(),
            tqh_last: &mut io_plugins.tqh_first,
        }
        //init
    };
}
#[used]
#[cfg_attr(target_os = "linux", link_section = ".init_array")]
#[cfg_attr(target_os = "windows", link_section = ".CRT$XIB")]
#[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
static INIT_ARRAY: [unsafe extern "C" fn(); 1] = [run_static_initializers];
